Add more Nt* functions.
[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 list      children;        /* list of children in Z-order */
60     struct list      unlinked;        /* list of children not linked in the Z-order list */
61     struct list      entry;           /* entry in parent's children list */
62     user_handle_t    handle;          /* full handle for this window */
63     struct thread   *thread;          /* thread owning the window */
64     struct window_class *class;       /* window class */
65     atom_t           atom;            /* class atom */
66     user_handle_t    last_active;     /* last active popup */
67     rectangle_t      window_rect;     /* window rectangle (relative to parent client area) */
68     rectangle_t      visible_rect;    /* visible part of window rect (relative to parent client area) */
69     rectangle_t      client_rect;     /* client rectangle (relative to parent client area) */
70     struct region   *win_region;      /* region for shaped windows (relative to window rect) */
71     struct region   *update_region;   /* update region (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     unsigned int     paint_flags;     /* various painting flags */
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 #define PAINT_INTERNAL  0x01  /* internal WM_PAINT pending */
87 #define PAINT_ERASE     0x02  /* needs WM_ERASEBKGND */
88 #define PAINT_NONCLIENT 0x04  /* needs WM_NCPAINT */
89
90 /* growable array of user handles */
91 struct user_handle_array
92 {
93     user_handle_t *handles;
94     int            count;
95     int            total;
96 };
97
98 static struct window *top_window;  /* top-level (desktop) window */
99
100 /* global window pointers */
101 static struct window *shell_window;
102 static struct window *shell_listview;
103 static struct window *progman_window;
104 static struct window *taskman_window;
105
106 /* retrieve a pointer to a window from its handle */
107 inline static struct window *get_window( user_handle_t handle )
108 {
109     struct window *ret = get_user_object( handle, USER_WINDOW );
110     if (!ret) set_error( STATUS_INVALID_HANDLE );
111     return ret;
112 }
113
114 /* change the parent of a window (or unlink the window if the new parent is NULL) */
115 static int set_parent_window( struct window *win, struct window *parent )
116 {
117     struct window *ptr;
118
119     /* make sure parent is not a child of window */
120     for (ptr = parent; ptr; ptr = ptr->parent)
121     {
122         if (ptr == win)
123         {
124             set_error( STATUS_INVALID_PARAMETER );
125             return 0;
126         }
127     }
128
129     list_remove( &win->entry );  /* unlink it from the previous location */
130
131     if (parent)
132     {
133         win->parent = parent;
134         list_add_head( &parent->children, &win->entry );
135
136         /* if parent belongs to a different thread, attach the two threads */
137         if (parent->thread && parent->thread != win->thread)
138             attach_thread_input( win->thread, parent->thread );
139     }
140     else  /* move it to parent unlinked list */
141     {
142         list_add_head( &win->parent->unlinked, &win->entry );
143     }
144     return 1;
145 }
146
147 /* get next window in Z-order list */
148 static inline struct window *get_next_window( struct window *win )
149 {
150     struct list *ptr = list_next( &win->parent->children, &win->entry );
151     if (ptr == &win->parent->unlinked) ptr = NULL;
152     return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
153 }
154
155 /* get previous window in Z-order list */
156 static inline struct window *get_prev_window( struct window *win )
157 {
158     struct list *ptr = list_prev( &win->parent->children, &win->entry );
159     if (ptr == &win->parent->unlinked) ptr = NULL;
160     return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
161 }
162
163 /* get first child in Z-order list */
164 static inline struct window *get_first_child( struct window *win )
165 {
166     struct list *ptr = list_head( &win->children );
167     return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
168 }
169
170 /* get last child in Z-order list */
171 static inline struct window *get_last_child( struct window *win )
172 {
173     struct list *ptr = list_tail( &win->children );
174     return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
175 }
176
177 /* append a user handle to a handle array */
178 static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle )
179 {
180     if (array->count >= array->total)
181     {
182         int new_total = max( array->total * 2, 32 );
183         user_handle_t *new_array = realloc( array->handles, new_total * sizeof(*new_array) );
184         if (!new_array)
185         {
186             free( array->handles );
187             set_error( STATUS_NO_MEMORY );
188             return 0;
189         }
190         array->handles = new_array;
191         array->total = new_total;
192     }
193     array->handles[array->count++] = handle;
194     return 1;
195 }
196
197 /* set a window property */
198 static void set_property( struct window *win, atom_t atom, obj_handle_t handle,
199                           enum property_type type )
200 {
201     int i, free = -1;
202     struct property *new_props;
203
204     /* check if it exists already */
205     for (i = 0; i < win->prop_inuse; i++)
206     {
207         if (win->properties[i].type == PROP_TYPE_FREE)
208         {
209             free = i;
210             continue;
211         }
212         if (win->properties[i].atom == atom)
213         {
214             win->properties[i].type = type;
215             win->properties[i].handle = handle;
216             return;
217         }
218     }
219
220     /* need to add an entry */
221     if (!grab_global_atom( atom )) return;
222     if (free == -1)
223     {
224         /* no free entry */
225         if (win->prop_inuse >= win->prop_alloc)
226         {
227             /* need to grow the array */
228             if (!(new_props = realloc( win->properties,
229                                        sizeof(*new_props) * (win->prop_alloc + 16) )))
230             {
231                 set_error( STATUS_NO_MEMORY );
232                 release_global_atom( atom );
233                 return;
234             }
235             win->prop_alloc += 16;
236             win->properties = new_props;
237         }
238         free = win->prop_inuse++;
239     }
240     win->properties[free].atom   = atom;
241     win->properties[free].type   = type;
242     win->properties[free].handle = handle;
243 }
244
245 /* remove a window property */
246 static obj_handle_t remove_property( struct window *win, atom_t atom )
247 {
248     int i;
249
250     for (i = 0; i < win->prop_inuse; i++)
251     {
252         if (win->properties[i].type == PROP_TYPE_FREE) continue;
253         if (win->properties[i].atom == atom)
254         {
255             release_global_atom( atom );
256             win->properties[i].type = PROP_TYPE_FREE;
257             return win->properties[i].handle;
258         }
259     }
260     /* FIXME: last error? */
261     return 0;
262 }
263
264 /* find a window property */
265 static obj_handle_t get_property( struct window *win, atom_t atom )
266 {
267     int i;
268
269     for (i = 0; i < win->prop_inuse; i++)
270     {
271         if (win->properties[i].type == PROP_TYPE_FREE) continue;
272         if (win->properties[i].atom == atom) return win->properties[i].handle;
273     }
274     /* FIXME: last error? */
275     return 0;
276 }
277
278 /* destroy all properties of a window */
279 inline static void destroy_properties( struct window *win )
280 {
281     int i;
282
283     if (!win->properties) return;
284     for (i = 0; i < win->prop_inuse; i++)
285     {
286         if (win->properties[i].type == PROP_TYPE_FREE) continue;
287         release_global_atom( win->properties[i].atom );
288     }
289     free( win->properties );
290 }
291
292 /* destroy a window */
293 static void destroy_window( struct window *win )
294 {
295     assert( win != top_window );
296
297     /* destroy all children */
298     while (!list_empty(&win->children))
299         destroy_window( LIST_ENTRY( list_head(&win->children), struct window, entry ));
300     while (!list_empty(&win->unlinked))
301         destroy_window( LIST_ENTRY( list_head(&win->unlinked), struct window, entry ));
302
303     if (win->thread->queue)
304     {
305         if (win->update_region) inc_queue_paint_count( win->thread, -1 );
306         if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( win->thread, -1 );
307         queue_cleanup_window( win->thread, win->handle );
308     }
309     /* reset global window pointers, if the corresponding window is destroyed */
310     if (win == shell_window) shell_window = NULL;
311     if (win == shell_listview) shell_listview = NULL;
312     if (win == progman_window) progman_window = NULL;
313     if (win == taskman_window) taskman_window = NULL;
314     assert( win->thread->desktop_users > 0 );
315     win->thread->desktop_users--;
316     free_user_handle( win->handle );
317     destroy_properties( win );
318     list_remove( &win->entry );
319     if (win->win_region) free_region( win->win_region );
320     if (win->update_region) free_region( win->update_region );
321     release_class( win->class );
322     if (win->text) free( win->text );
323     memset( win, 0x55, sizeof(*win) + win->nb_extra_bytes - 1 );
324     free( win );
325 }
326
327 /* create a new window structure (note: the window is not linked in the window tree) */
328 static struct window *create_window( struct window *parent, struct window *owner,
329                                      atom_t atom, void *instance )
330 {
331     int extra_bytes;
332     struct window *win;
333     struct window_class *class = grab_class( current->process, atom, instance, &extra_bytes );
334
335     if (!class) return NULL;
336
337     win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
338     if (!win)
339     {
340         release_class( class );
341         return NULL;
342     }
343     if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) goto failed;
344
345     win->parent         = parent;
346     win->owner          = owner ? owner->handle : 0;
347     win->thread         = current;
348     win->class          = class;
349     win->atom           = atom;
350     win->last_active    = win->handle;
351     win->win_region     = NULL;
352     win->update_region  = NULL;
353     win->style          = 0;
354     win->ex_style       = 0;
355     win->id             = 0;
356     win->instance       = NULL;
357     win->user_data      = NULL;
358     win->text           = NULL;
359     win->paint_flags    = 0;
360     win->prop_inuse     = 0;
361     win->prop_alloc     = 0;
362     win->properties     = NULL;
363     win->nb_extra_bytes = extra_bytes;
364     memset( win->extra_bytes, 0, extra_bytes );
365     list_init( &win->children );
366     list_init( &win->unlinked );
367
368     /* if parent belongs to a different thread, attach the two threads */
369     if (parent && parent->thread && parent->thread != current)
370     {
371         if (!attach_thread_input( current, parent->thread )) goto failed;
372     }
373     else  /* otherwise just make sure that the thread has a message queue */
374     {
375         if (!current->queue && !init_thread_queue( current )) goto failed;
376     }
377
378     /* put it on parent unlinked list */
379     if (parent) list_add_head( &parent->unlinked, &win->entry );
380
381     current->desktop_users++;
382     return win;
383
384 failed:
385     if (win->handle) free_user_handle( win->handle );
386     release_class( class );
387     free( win );
388     return NULL;
389 }
390
391 /* destroy all windows belonging to a given thread */
392 void destroy_thread_windows( struct thread *thread )
393 {
394     user_handle_t handle = 0;
395     struct window *win;
396
397     while ((win = next_user_handle( &handle, USER_WINDOW )))
398     {
399         if (win->thread != thread) continue;
400         destroy_window( win );
401     }
402 }
403
404 /* check whether child is a descendant of parent */
405 int is_child_window( user_handle_t parent, user_handle_t child )
406 {
407     struct window *child_ptr = get_user_object( child, USER_WINDOW );
408     struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
409
410     if (!child_ptr || !parent_ptr) return 0;
411     while (child_ptr->parent)
412     {
413         if (child_ptr->parent == parent_ptr) return 1;
414         child_ptr = child_ptr->parent;
415     }
416     return 0;
417 }
418
419 /* check whether window is a top-level window */
420 int is_top_level_window( user_handle_t window )
421 {
422     struct window *win = get_user_object( window, USER_WINDOW );
423     return (win && win->parent == top_window);
424 }
425
426 /* make a window active if possible */
427 int make_window_active( user_handle_t window )
428 {
429     struct window *owner, *win = get_window( window );
430
431     if (!win) return 0;
432
433     /* set last active for window and its owner */
434     win->last_active = win->handle;
435     if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
436     return 1;
437 }
438
439 /* increment (or decrement) the window paint count */
440 static inline void inc_window_paint_count( struct window *win, int incr )
441 {
442     if (win->thread) inc_queue_paint_count( win->thread, incr );
443 }
444
445 /* check if window and all its ancestors are visible */
446 static int is_visible( const struct window *win )
447 {
448     while (win && win != top_window)
449     {
450         if (!(win->style & WS_VISIBLE)) return 0;
451         win = win->parent;
452         /* if parent is minimized children are not visible */
453         if (win && (win->style & WS_MINIMIZE)) return 0;
454     }
455     return 1;
456 }
457
458 /* same as is_visible but takes a window handle */
459 int is_window_visible( user_handle_t window )
460 {
461     struct window *win = get_user_object( window, USER_WINDOW );
462     if (!win) return 0;
463     return is_visible( win );
464 }
465
466 /* check if point is inside the window */
467 static inline int is_point_in_window( struct window *win, int x, int y )
468 {
469     if (!(win->style & WS_VISIBLE)) return 0; /* not visible */
470     if ((win->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
471         return 0;  /* disabled child */
472     if ((win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
473         return 0;  /* transparent */
474     if (x < win->visible_rect.left || x >= win->visible_rect.right ||
475         y < win->visible_rect.top || y >= win->visible_rect.bottom)
476         return 0;  /* not in window */
477     if (win->win_region &&
478         !point_in_region( win->win_region, x - win->window_rect.left, y - win->window_rect.top ))
479         return 0;  /* not in window region */
480     return 1;
481 }
482
483 /* find child of 'parent' that contains the given point (in parent-relative coords) */
484 static struct window *child_window_from_point( struct window *parent, int x, int y )
485 {
486     struct window *ptr;
487
488     LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
489     {
490         if (!is_point_in_window( ptr, x, y )) continue;  /* skip it */
491
492         /* if window is minimized or disabled, return at once */
493         if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
494
495         /* if point is not in client area, return at once */
496         if (x < ptr->client_rect.left || x >= ptr->client_rect.right ||
497             y < ptr->client_rect.top || y >= ptr->client_rect.bottom)
498             return ptr;
499
500         return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top );
501     }
502     return parent;  /* not found any child */
503 }
504
505 /* find all children of 'parent' that contain the given point */
506 static int get_window_children_from_point( struct window *parent, int x, int y,
507                                            struct user_handle_array *array )
508 {
509     struct window *ptr;
510
511     LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
512     {
513         if (!is_point_in_window( ptr, x, y )) continue;  /* skip it */
514
515         /* if point is in client area, and window is not minimized or disabled, check children */
516         if (!(ptr->style & (WS_MINIMIZE|WS_DISABLED)) &&
517             x >= ptr->client_rect.left && x < ptr->client_rect.right &&
518             y >= ptr->client_rect.top && y < ptr->client_rect.bottom)
519         {
520             if (!get_window_children_from_point( ptr, x - ptr->client_rect.left,
521                                                  y - ptr->client_rect.top, array ))
522                 return 0;
523         }
524
525         /* now add window to the array */
526         if (!add_handle_to_array( array, ptr->handle )) return 0;
527     }
528     return 1;
529 }
530
531 /* find window containing point (in absolute coords) */
532 user_handle_t window_from_point( int x, int y )
533 {
534     struct window *ret;
535
536     if (!top_window) return 0;
537     ret = child_window_from_point( top_window, x, y );
538     return ret->handle;
539 }
540
541 /* return list of all windows containing point (in absolute coords) */
542 static int all_windows_from_point( struct window *top, int x, int y, struct user_handle_array *array )
543 {
544     struct window *ptr;
545
546     /* make point relative to top window */
547     for (ptr = top->parent; ptr && ptr != top_window; ptr = ptr->parent)
548     {
549         x -= ptr->client_rect.left;
550         y -= ptr->client_rect.top;
551     }
552
553     if (!is_point_in_window( top, x, y )) return 1;
554
555     /* if point is in client area, and window is not minimized or disabled, check children */
556     if (!(top->style & (WS_MINIMIZE|WS_DISABLED)) &&
557         x >= top->client_rect.left && x < top->client_rect.right &&
558         y >= top->client_rect.top && y < top->client_rect.bottom)
559     {
560         if (!get_window_children_from_point( top, x - top->client_rect.left,
561                                              y - top->client_rect.top, array ))
562             return 0;
563     }
564     /* now add window to the array */
565     if (!add_handle_to_array( array, top->handle )) return 0;
566     return 1;
567 }
568
569
570 /* return the thread owning a window */
571 struct thread *get_window_thread( user_handle_t handle )
572 {
573     struct window *win = get_user_object( handle, USER_WINDOW );
574     if (!win || !win->thread) return NULL;
575     return (struct thread *)grab_object( win->thread );
576 }
577
578
579 /* check if any area of a window needs repainting */
580 static inline int win_needs_repaint( struct window *win )
581 {
582     return win->update_region || (win->paint_flags & PAINT_INTERNAL);
583 }
584
585
586 /* find a child of the specified window that needs repainting */
587 static struct window *find_child_to_repaint( struct window *parent, struct thread *thread )
588 {
589     struct window *ptr, *ret = NULL;
590
591     LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
592     {
593         if (!(ptr->style & WS_VISIBLE)) continue;
594         if (ptr->thread == thread && win_needs_repaint( ptr ))
595             ret = ptr;
596         else if (!(ptr->style & WS_MINIMIZE)) /* explore its children */
597             ret = find_child_to_repaint( ptr, thread );
598         if (ret) break;
599     }
600
601     if (ret && (ret->ex_style & WS_EX_TRANSPARENT))
602     {
603         /* transparent window, check for non-transparent sibling to paint first */
604         for (ptr = get_next_window(ret); ptr; ptr = get_next_window(ptr))
605         {
606             if (!(ptr->style & WS_VISIBLE)) continue;
607             if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
608             if (ptr->thread != thread) continue;
609             if (win_needs_repaint( ptr )) return ptr;
610         }
611     }
612     return ret;
613 }
614
615
616 /* find a window that needs to receive a WM_PAINT; also clear its internal paint flag */
617 user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread )
618 {
619     struct window *ptr, *win = find_child_to_repaint( top_window, thread );
620
621     if (win && parent)
622     {
623         /* check that it is a child of the specified parent */
624         for (ptr = win; ptr; ptr = ptr->parent)
625             if (ptr->handle == parent) break;
626         /* otherwise don't return any window, we don't repaint a child before its parent */
627         if (!ptr) win = NULL;
628     }
629     if (!win) return 0;
630     win->paint_flags &= ~PAINT_INTERNAL;
631     return win->handle;
632 }
633
634
635 /* intersect the window region with the specified region, relative to the window parent */
636 static struct region *intersect_window_region( struct region *region, struct window *win )
637 {
638     /* make region relative to window rect */
639     offset_region( region, -win->window_rect.left, -win->window_rect.top );
640     if (!intersect_region( region, region, win->win_region )) return NULL;
641     /* make region relative to parent again */
642     offset_region( region, win->window_rect.left, win->window_rect.top );
643     return region;
644 }
645
646
647 /* convert coordinates from client to screen coords */
648 static inline void client_to_screen( struct window *win, int *x, int *y )
649 {
650     for ( ; win; win = win->parent)
651     {
652         *x += win->client_rect.left;
653         *y += win->client_rect.top;
654     }
655 }
656
657 /* map the region from window to screen coordinates */
658 static inline void map_win_region_to_screen( struct window *win, struct region *region )
659 {
660     int x = win->window_rect.left;
661     int y = win->window_rect.top;
662     client_to_screen( win->parent, &x, &y );
663     offset_region( region, x, y );
664 }
665
666
667 /* clip all children of a given window out of the visible region */
668 static struct region *clip_children( struct window *parent, struct window *last,
669                                      struct region *region, int offset_x, int offset_y )
670 {
671     struct window *ptr;
672     struct region *tmp = create_empty_region();
673
674     if (!tmp) return NULL;
675     LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
676     {
677         if (ptr == last) break;
678         if (!(ptr->style & WS_VISIBLE)) continue;
679         if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
680         set_region_rect( tmp, &ptr->visible_rect );
681         if (ptr->win_region && !intersect_window_region( tmp, ptr ))
682         {
683             free_region( tmp );
684             return NULL;
685         }
686         offset_region( tmp, offset_x, offset_y );
687         if (!(region = subtract_region( region, region, tmp ))) break;
688         if (is_region_empty( region )) break;
689     }
690     free_region( tmp );
691     return region;
692 }
693
694
695 /* compute the intersection of two rectangles; return 0 if the result is empty */
696 static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, const rectangle_t *src2 )
697 {
698     dst->left   = max( src1->left, src2->left );
699     dst->top    = max( src1->top, src2->top );
700     dst->right  = min( src1->right, src2->right );
701     dst->bottom = min( src1->bottom, src2->bottom );
702     return (dst->left < dst->right && dst->top < dst->bottom);
703 }
704
705
706 /* set the region to the client rect clipped by the window rect, in parent-relative coordinates */
707 static void set_region_client_rect( struct region *region, struct window *win )
708 {
709     rectangle_t rect;
710
711     intersect_rect( &rect, &win->window_rect, &win->client_rect );
712     set_region_rect( region, &rect );
713 }
714
715
716 /* get the top-level window to clip against for a given window */
717 static inline struct window *get_top_clipping_window( struct window *win )
718 {
719     while (win->parent && win->parent != top_window) win = win->parent;
720     return win;
721 }
722
723
724 /* compute the visible region of a window, in window coordinates */
725 static struct region *get_visible_region( struct window *win, struct window *top, unsigned int flags )
726 {
727     struct region *tmp = NULL, *region;
728     int offset_x, offset_y;
729
730     if (!(region = create_empty_region())) return NULL;
731
732     /* first check if all ancestors are visible */
733
734     if (!is_visible( win )) return region;  /* empty region */
735
736     /* create a region relative to the window itself */
737
738     if ((flags & DCX_PARENTCLIP) && win != top && win->parent)
739     {
740         set_region_client_rect( region, win->parent );
741         offset_region( region, -win->parent->client_rect.left, -win->parent->client_rect.top );
742     }
743     else if (flags & DCX_WINDOW)
744     {
745         set_region_rect( region, &win->visible_rect );
746         if (win->win_region && !intersect_window_region( region, win )) goto error;
747     }
748     else
749     {
750         set_region_client_rect( region, win );
751         if (win->win_region && !intersect_window_region( region, win )) goto error;
752     }
753     offset_x = win->window_rect.left;
754     offset_y = win->window_rect.top;
755
756     /* clip children */
757
758     if (flags & DCX_CLIPCHILDREN)
759     {
760         if (!clip_children( win, NULL, region, win->client_rect.left, win->client_rect.top ))
761             goto error;
762     }
763
764     /* clip siblings of ancestors */
765
766     if (top && top != win && (tmp = create_empty_region()) != NULL)
767     {
768         while (win != top && win->parent)
769         {
770             if (win->style & WS_CLIPSIBLINGS)
771             {
772                 if (!clip_children( win->parent, win, region, 0, 0 )) goto error;
773                 if (is_region_empty( region )) break;
774             }
775             /* clip to parent client area */
776             win = win->parent;
777             offset_x += win->client_rect.left;
778             offset_y += win->client_rect.top;
779             offset_region( region, win->client_rect.left, win->client_rect.top );
780             set_region_client_rect( tmp, win );
781             if (win->win_region && !intersect_window_region( tmp, win )) goto error;
782             if (!intersect_region( region, region, tmp )) goto error;
783             if (is_region_empty( region )) break;
784         }
785         free_region( tmp );
786     }
787     offset_region( region, -offset_x, -offset_y );  /* make it relative to target window */
788     return region;
789
790 error:
791     if (tmp) free_region( tmp );
792     free_region( region );
793     return NULL;
794 }
795
796
797 /* get the window class of a window */
798 struct window_class* get_window_class( user_handle_t window )
799 {
800     struct window *win;
801     if (!(win = get_window( window ))) return NULL;
802     return win->class;
803 }
804
805 /* return a copy of the specified region cropped to the window client or frame rectangle, */
806 /* and converted from client to window coordinates. Helper for (in)validate_window. */
807 static struct region *crop_region_to_win_rect( struct window *win, struct region *region, int frame )
808 {
809     struct region *tmp = create_empty_region();
810
811     if (!tmp) return NULL;
812
813     /* get bounding rect in client coords */
814     if (frame) set_region_rect( tmp, &win->window_rect );
815     else set_region_client_rect( tmp, win );
816     offset_region( tmp, -win->client_rect.left, -win->client_rect.top );
817
818     /* intersect specified region with bounding rect */
819     if (region && !intersect_region( tmp, region, tmp )) goto done;
820     if (is_region_empty( tmp )) goto done;
821
822     /* map it to window coords */
823     offset_region( tmp, win->client_rect.left - win->window_rect.left,
824                    win->client_rect.top - win->window_rect.top );
825     return tmp;
826
827 done:
828     free_region( tmp );
829     return NULL;
830 }
831
832
833 /* set a region as new update region for the window */
834 static void set_update_region( struct window *win, struct region *region )
835 {
836     if (region && !is_region_empty( region ))
837     {
838         if (!win->update_region) inc_window_paint_count( win, 1 );
839         else free_region( win->update_region );
840         win->update_region = region;
841     }
842     else
843     {
844         if (win->update_region)
845         {
846             inc_window_paint_count( win, -1 );
847             free_region( win->update_region );
848         }
849         win->paint_flags &= ~(PAINT_ERASE | PAINT_NONCLIENT);
850         win->update_region = NULL;
851         if (region) free_region( region );
852     }
853 }
854
855
856 /* add a region to the update region; the passed region is freed or reused */
857 static int add_update_region( struct window *win, struct region *region )
858 {
859     if (win->update_region && !union_region( region, win->update_region, region ))
860     {
861         free_region( region );
862         return 0;
863     }
864     set_update_region( win, region );
865     return 1;
866 }
867
868
869 /* validate the non client area of a window */
870 static void validate_non_client( struct window *win )
871 {
872     struct region *tmp;
873     rectangle_t rect;
874
875     if (!win->update_region) return;  /* nothing to do */
876
877     /* get client rect in window coords */
878     rect.left   = win->client_rect.left - win->window_rect.left;
879     rect.top    = win->client_rect.top - win->window_rect.top;
880     rect.right  = win->client_rect.right - win->window_rect.left;
881     rect.bottom = win->client_rect.bottom - win->window_rect.top;
882
883     if ((tmp = create_empty_region()))
884     {
885         set_region_rect( tmp, &rect );
886         if (intersect_region( tmp, win->update_region, tmp ))
887             set_update_region( win, tmp );
888         else
889             free_region( tmp );
890     }
891     win->paint_flags &= ~PAINT_NONCLIENT;
892 }
893
894
895 /* validate a window completely so that we don't get any further paint messages for it */
896 static void validate_whole_window( struct window *win )
897 {
898     set_update_region( win, NULL );
899
900     if (win->paint_flags & PAINT_INTERNAL)
901     {
902         win->paint_flags &= ~PAINT_INTERNAL;
903         inc_window_paint_count( win, -1 );
904     }
905 }
906
907
908 /* validate the update region of a window on all parents; helper for redraw_window */
909 static void validate_parents( struct window *child )
910 {
911     int offset_x = 0, offset_y = 0;
912     struct window *win = child;
913     struct region *tmp = NULL;
914
915     if (!child->update_region) return;
916
917     while (win->parent && win->parent != top_window)
918     {
919         /* map to parent client coords */
920         offset_x += win->window_rect.left;
921         offset_y += win->window_rect.top;
922
923         win = win->parent;
924
925         /* and now map to window coords */
926         offset_x += win->client_rect.left - win->window_rect.left;
927         offset_y += win->client_rect.top - win->window_rect.top;
928
929         if (win->update_region && !(win->style & WS_CLIPCHILDREN))
930         {
931             if (!tmp && !(tmp = create_empty_region())) return;
932             offset_region( child->update_region, offset_x, offset_y );
933             if (subtract_region( tmp, win->update_region, child->update_region ))
934             {
935                 set_update_region( win, tmp );
936                 tmp = NULL;
937             }
938             /* restore child coords */
939             offset_region( child->update_region, -offset_x, -offset_y );
940         }
941     }
942     if (tmp) free_region( tmp );
943 }
944
945
946 /* add/subtract a region (in client coordinates) to the update region of the window */
947 static void redraw_window( struct window *win, struct region *region, int frame, unsigned int flags )
948 {
949     struct region *tmp;
950     struct window *child;
951
952     if (flags & RDW_INVALIDATE)
953     {
954         if (!(tmp = crop_region_to_win_rect( win, region, frame ))) return;
955
956         if (!add_update_region( win, tmp )) return;
957
958         if (flags & RDW_FRAME) win->paint_flags |= PAINT_NONCLIENT;
959         if (flags & RDW_ERASE) win->paint_flags |= PAINT_ERASE;
960     }
961     else if (flags & RDW_VALIDATE)
962     {
963         if (!region && (flags & RDW_NOFRAME))  /* shortcut: validate everything */
964         {
965             set_update_region( win, NULL );
966         }
967         else if (win->update_region)
968         {
969             if ((tmp = crop_region_to_win_rect( win, region, frame )))
970             {
971                 if (!subtract_region( tmp, win->update_region, tmp ))
972                 {
973                     free_region( tmp );
974                     return;
975                 }
976                 set_update_region( win, tmp );
977             }
978             if (flags & RDW_NOFRAME) validate_non_client( win );
979             if (flags & RDW_NOERASE) win->paint_flags &= ~PAINT_ERASE;
980         }
981     }
982
983     if ((flags & RDW_INTERNALPAINT) && !(win->paint_flags & PAINT_INTERNAL))
984     {
985         win->paint_flags |= PAINT_INTERNAL;
986         inc_window_paint_count( win, 1 );
987     }
988     else if ((flags & RDW_NOINTERNALPAINT) && (win->paint_flags & PAINT_INTERNAL))
989     {
990         win->paint_flags &= ~PAINT_INTERNAL;
991         inc_window_paint_count( win, -1 );
992     }
993
994     if (flags & RDW_UPDATENOW)
995     {
996         validate_parents( win );
997         flags &= ~RDW_UPDATENOW;
998     }
999
1000     /* now process children recursively */
1001
1002     if (flags & RDW_NOCHILDREN) return;
1003     if (win->style & WS_MINIMIZE) return;
1004     if ((win->style & WS_CLIPCHILDREN) && !(flags & RDW_ALLCHILDREN)) return;
1005
1006     if (!(tmp = crop_region_to_win_rect( win, region, 0 ))) return;
1007
1008     /* map to client coordinates */
1009     offset_region( tmp, win->window_rect.left - win->client_rect.left,
1010                    win->window_rect.top - win->client_rect.top );
1011
1012     if (flags & RDW_INVALIDATE) flags |= RDW_FRAME | RDW_ERASE;
1013
1014     LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry )
1015     {
1016         if (!(child->style & WS_VISIBLE)) continue;
1017         if (!rect_in_region( tmp, &child->window_rect )) continue;
1018         offset_region( tmp, -child->client_rect.left, -child->client_rect.top );
1019         redraw_window( child, tmp, 1, flags );
1020         offset_region( tmp, child->client_rect.left, child->client_rect.top );
1021     }
1022     free_region( tmp );
1023 }
1024
1025
1026 /* retrieve the update flags for a window depending on the state of the update region */
1027 static unsigned int get_update_flags( struct window *win, unsigned int flags )
1028 {
1029     unsigned int ret = 0;
1030
1031     if (flags & UPDATE_NONCLIENT)
1032     {
1033         if ((win->paint_flags & PAINT_NONCLIENT) && win->update_region) ret |= UPDATE_NONCLIENT;
1034     }
1035     if (flags & UPDATE_ERASE)
1036     {
1037         if ((win->paint_flags & PAINT_ERASE) && win->update_region) ret |= UPDATE_ERASE;
1038     }
1039     if (flags & UPDATE_PAINT)
1040     {
1041         if (win->update_region) ret |= UPDATE_PAINT;
1042     }
1043     if (flags & UPDATE_INTERNALPAINT)
1044     {
1045         if (win->paint_flags & PAINT_INTERNAL) ret |= UPDATE_INTERNALPAINT;
1046     }
1047     return ret;
1048 }
1049
1050
1051 /* iterate through the children of the given window until we find one with some update flags */
1052 static unsigned int get_child_update_flags( struct window *win, struct window *from_child,
1053                                             unsigned int flags, struct window **child )
1054 {
1055     struct window *ptr;
1056     unsigned int ret = 0;
1057
1058     /* first make sure we want to iterate children at all */
1059
1060     if (win->style & WS_MINIMIZE) return 0;
1061
1062     /* note: the WS_CLIPCHILDREN test is the opposite of the invalidation case,
1063      * here we only want to repaint children of windows that clip them, others
1064      * need to wait for WM_PAINT to be done in the parent first.
1065      */
1066     if (!(flags & UPDATE_ALLCHILDREN) && !(win->style & WS_CLIPCHILDREN)) return 0;
1067
1068     LIST_FOR_EACH_ENTRY( ptr, &win->children, struct window, entry )
1069     {
1070         if (from_child)  /* skip all children until from_child is found */
1071         {
1072             if (ptr == from_child) from_child = NULL;
1073             continue;
1074         }
1075         if (!(ptr->style & WS_VISIBLE)) continue;
1076         if ((ret = get_update_flags( ptr, flags )) != 0)
1077         {
1078             *child = ptr;
1079             break;
1080         }
1081         if ((ret = get_child_update_flags( ptr, NULL, flags, child ))) break;
1082     }
1083     return ret;
1084 }
1085
1086 /* iterate through children and siblings of the given window until we find one with some update flags */
1087 static unsigned int get_window_update_flags( struct window *win, struct window *from_child,
1088                                              unsigned int flags, struct window **child )
1089 {
1090     unsigned int ret;
1091     struct window *ptr, *from_sibling = NULL;
1092
1093     /* if some parent is not visible start from the next sibling */
1094
1095     if (!is_visible( win )) return 0;
1096     for (ptr = from_child; ptr && ptr != top_window; ptr = ptr->parent)
1097     {
1098         if (!(ptr->style & WS_VISIBLE) || (ptr->style & WS_MINIMIZE)) from_sibling = ptr;
1099         if (ptr == win) break;
1100     }
1101
1102     /* non-client painting must be delayed if one of the parents is going to
1103      * be repainted and doesn't clip children */
1104
1105     if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT)))
1106     {
1107         for (ptr = win->parent; ptr && ptr != top_window; ptr = ptr->parent)
1108         {
1109             if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr ))
1110                 return 0;
1111         }
1112         if (from_child && !(flags & UPDATE_ALLCHILDREN))
1113         {
1114             for (ptr = from_sibling ? from_sibling : from_child;
1115                  ptr && ptr != top_window; ptr = ptr->parent)
1116             {
1117                 if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) from_sibling = ptr;
1118                 if (ptr == win) break;
1119             }
1120         }
1121     }
1122
1123
1124     /* check window itself (only if not restarting from a child) */
1125
1126     if (!from_child)
1127     {
1128         if ((ret = get_update_flags( win, flags )))
1129         {
1130             *child = win;
1131             return ret;
1132         }
1133         from_child = win;
1134     }
1135
1136     /* now check children */
1137
1138     if (flags & UPDATE_NOCHILDREN) return 0;
1139     if (!from_sibling)
1140     {
1141         if ((ret = get_child_update_flags( from_child, NULL, flags, child ))) return ret;
1142         from_sibling = from_child;
1143     }
1144
1145     /* then check siblings and parent siblings */
1146
1147     while (from_sibling->parent && from_sibling != win)
1148     {
1149         if ((ret = get_child_update_flags( from_sibling->parent, from_sibling, flags, child )))
1150             return ret;
1151         from_sibling = from_sibling->parent;
1152     }
1153     return 0;
1154 }
1155
1156
1157 /* expose a region of a window, looking for the top most parent that needs to be exposed */
1158 /* the region is in window coordinates */
1159 static void expose_window( struct window *win, struct window *top, struct region *region )
1160 {
1161     struct window *parent, *ptr;
1162     int offset_x, offset_y;
1163
1164     /* find the top most parent that doesn't clip either siblings or children */
1165     for (parent = ptr = win; ptr != top; ptr = ptr->parent)
1166     {
1167         if (!(ptr->style & WS_CLIPCHILDREN)) parent = ptr;
1168         if (!(ptr->style & WS_CLIPSIBLINGS)) parent = ptr->parent;
1169     }
1170     if (parent == win && parent != top && win->parent)
1171         parent = win->parent;  /* always go up at least one level if possible */
1172
1173     offset_x = win->window_rect.left - win->client_rect.left;
1174     offset_y = win->window_rect.top - win->client_rect.top;
1175     for (ptr = win; ptr != parent; ptr = ptr->parent)
1176     {
1177         offset_x += ptr->client_rect.left;
1178         offset_y += ptr->client_rect.top;
1179     }
1180     offset_region( region, offset_x, offset_y );
1181     redraw_window( parent, region, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
1182     offset_region( region, -offset_x, -offset_y );
1183 }
1184
1185
1186 /* set the window and client rectangles, updating the update region if necessary */
1187 static void set_window_pos( struct window *win, struct window *previous,
1188                             unsigned int swp_flags, const rectangle_t *window_rect,
1189                             const rectangle_t *client_rect, const rectangle_t *visible_rect,
1190                             const rectangle_t *valid_rects )
1191 {
1192     struct region *old_vis_rgn = NULL, *new_vis_rgn;
1193     const rectangle_t old_window_rect = win->window_rect;
1194     const rectangle_t old_visible_rect = win->visible_rect;
1195     const rectangle_t old_client_rect = win->client_rect;
1196     struct window *top = get_top_clipping_window( win );
1197     int visible = (win->style & WS_VISIBLE) || (swp_flags & SWP_SHOWWINDOW);
1198
1199     if (win->parent && !is_visible( win->parent )) visible = 0;
1200
1201     if (visible && !(old_vis_rgn = get_visible_region( win, top, DCX_WINDOW ))) return;
1202
1203     /* set the new window info before invalidating anything */
1204
1205     win->window_rect  = *window_rect;
1206     win->visible_rect = *visible_rect;
1207     win->client_rect  = *client_rect;
1208     if (!(swp_flags & SWP_NOZORDER) && win->parent)
1209     {
1210         list_remove( &win->entry );  /* unlink it from the previous location */
1211         if (previous) list_add_after( &previous->entry, &win->entry );
1212         else list_add_head( &win->parent->children, &win->entry );
1213     }
1214     if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE;
1215     else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE;
1216
1217     /* if the window is not visible, everything is easy */
1218     if (!visible) return;
1219
1220     if (!(new_vis_rgn = get_visible_region( win, top, DCX_WINDOW )))
1221     {
1222         free_region( old_vis_rgn );
1223         clear_error();  /* ignore error since the window info has been modified already */
1224         return;
1225     }
1226
1227     /* expose anything revealed by the change */
1228
1229     if (!(swp_flags & SWP_NOREDRAW))
1230     {
1231         offset_region( old_vis_rgn, old_window_rect.left - window_rect->left,
1232                        old_window_rect.top - window_rect->top );
1233         if (xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
1234             expose_window( win, top, new_vis_rgn );
1235     }
1236     free_region( old_vis_rgn );
1237
1238     if (!(win->style & WS_VISIBLE))
1239     {
1240         /* clear the update region since the window is no longer visible */
1241         validate_whole_window( win );
1242         goto done;
1243     }
1244
1245     /* crop update region to the new window rect */
1246
1247     if (win->update_region &&
1248         (window_rect->right - window_rect->left < old_window_rect.right - old_window_rect.left ||
1249          window_rect->bottom - window_rect->top < old_window_rect.bottom - old_window_rect.top))
1250     {
1251         struct region *tmp = create_empty_region();
1252         if (tmp)
1253         {
1254             set_region_rect( tmp, window_rect );
1255             offset_region( tmp, -window_rect->left, -window_rect->top );
1256             if (intersect_region( tmp, win->update_region, tmp ))
1257                 set_update_region( win, tmp );
1258             else
1259                 free_region( tmp );
1260         }
1261     }
1262
1263     if (swp_flags & SWP_NOREDRAW) goto done;  /* do not repaint anything */
1264
1265     /* expose the whole non-client area if it changed in any way */
1266
1267     if ((swp_flags & SWP_FRAMECHANGED) ||
1268         memcmp( window_rect, &old_window_rect, sizeof(old_window_rect) ) ||
1269         memcmp( visible_rect, &old_visible_rect, sizeof(old_visible_rect) ) ||
1270         memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ))
1271     {
1272         struct region *tmp = create_empty_region();
1273
1274         if (tmp)
1275         {
1276             /* subtract the valid portion of client rect from the total region */
1277             if (!memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ))
1278                 set_region_rect( tmp, client_rect );
1279             else if (valid_rects)
1280                 set_region_rect( tmp, &valid_rects[0] );
1281
1282             set_region_rect( new_vis_rgn, window_rect );
1283             if (subtract_region( tmp, new_vis_rgn, tmp ))
1284             {
1285                 offset_region( tmp, -client_rect->left, -client_rect->top );
1286                 redraw_window( win, tmp, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
1287             }
1288             free_region( tmp );
1289         }
1290     }
1291
1292 done:
1293     free_region( new_vis_rgn );
1294     clear_error();  /* we ignore out of memory errors once the new rects have been set */
1295 }
1296
1297
1298 /* create a window */
1299 DECL_HANDLER(create_window)
1300 {
1301     struct window *win;
1302
1303     reply->handle = 0;
1304     if (!req->parent)  /* return desktop window */
1305     {
1306         if (!top_window)
1307         {
1308             if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return;
1309             current->desktop_users--;
1310             top_window->thread = NULL;  /* no thread owns the desktop */
1311             top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1312         }
1313         win = top_window;
1314     }
1315     else
1316     {
1317         struct window *parent, *owner = NULL;
1318
1319         if (!(parent = get_window( req->parent ))) return;
1320         if (req->owner && !(owner = get_window( req->owner ))) return;
1321         if (owner == top_window) owner = NULL;
1322         else if (owner && parent != top_window)
1323         {
1324             /* an owned window must be created as top-level */
1325             set_error( STATUS_ACCESS_DENIED );
1326             return;
1327         }
1328         if (!(win = create_window( parent, owner, req->atom, req->instance ))) return;
1329     }
1330     reply->handle    = win->handle;
1331     reply->extra     = win->nb_extra_bytes;
1332     reply->class_ptr = get_class_client_ptr( win->class );
1333 }
1334
1335
1336 /* set the parent of a window */
1337 DECL_HANDLER(set_parent)
1338 {
1339     struct window *win, *parent = NULL;
1340
1341     if (!(win = get_window( req->handle ))) return;
1342     if (req->parent && !(parent = get_window( req->parent ))) return;
1343
1344     if (win == top_window)
1345     {
1346         set_error( STATUS_INVALID_PARAMETER );
1347         return;
1348     }
1349     reply->old_parent  = win->parent->handle;
1350     reply->full_parent = parent ? parent->handle : 0;
1351     set_parent_window( win, parent );
1352 }
1353
1354
1355 /* destroy a window */
1356 DECL_HANDLER(destroy_window)
1357 {
1358     struct window *win = get_window( req->handle );
1359     if (win)
1360     {
1361         if (win != top_window) destroy_window( win );
1362         else set_error( STATUS_ACCESS_DENIED );
1363     }
1364 }
1365
1366
1367 /* set a window owner */
1368 DECL_HANDLER(set_window_owner)
1369 {
1370     struct window *win = get_window( req->handle );
1371     struct window *owner = NULL;
1372
1373     if (!win) return;
1374     if (req->owner && !(owner = get_window( req->owner ))) return;
1375     if (win == top_window)
1376     {
1377         set_error( STATUS_ACCESS_DENIED );
1378         return;
1379     }
1380     reply->prev_owner = win->owner;
1381     reply->full_owner = win->owner = owner ? owner->handle : 0;
1382 }
1383
1384
1385 /* get information from a window handle */
1386 DECL_HANDLER(get_window_info)
1387 {
1388     struct window *win = get_window( req->handle );
1389
1390     reply->full_handle = 0;
1391     reply->tid = reply->pid = 0;
1392     if (win)
1393     {
1394         reply->full_handle = win->handle;
1395         reply->last_active = win->handle;
1396         if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active;
1397         if (win->thread)
1398         {
1399             reply->tid  = get_thread_id( win->thread );
1400             reply->pid  = get_process_id( win->thread->process );
1401             reply->atom = get_class_atom( win->class );
1402         }
1403     }
1404 }
1405
1406
1407 /* set some information in a window */
1408 DECL_HANDLER(set_window_info)
1409 {
1410     struct window *win = get_window( req->handle );
1411
1412     if (!win) return;
1413     if (req->flags && win == top_window)
1414     {
1415         set_error( STATUS_ACCESS_DENIED );
1416         return;
1417     }
1418     if (req->extra_size > sizeof(req->extra_value) ||
1419         req->extra_offset < -1 ||
1420         req->extra_offset > win->nb_extra_bytes - (int)req->extra_size)
1421     {
1422         set_win32_error( ERROR_INVALID_INDEX );
1423         return;
1424     }
1425     if (req->extra_offset != -1)
1426     {
1427         memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, req->extra_size );
1428     }
1429     else if (req->flags & SET_WIN_EXTRA)
1430     {
1431         set_win32_error( ERROR_INVALID_INDEX );
1432         return;
1433     }
1434     reply->old_style     = win->style;
1435     reply->old_ex_style  = win->ex_style;
1436     reply->old_id        = win->id;
1437     reply->old_instance  = win->instance;
1438     reply->old_user_data = win->user_data;
1439     if (req->flags & SET_WIN_STYLE) win->style = req->style;
1440     if (req->flags & SET_WIN_EXSTYLE) win->ex_style = req->ex_style;
1441     if (req->flags & SET_WIN_ID) win->id = req->id;
1442     if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance;
1443     if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data;
1444     if (req->flags & SET_WIN_EXTRA) memcpy( win->extra_bytes + req->extra_offset,
1445                                             &req->extra_value, req->extra_size );
1446
1447     /* changing window style triggers a non-client paint */
1448     if (req->flags & SET_WIN_STYLE) win->paint_flags |= PAINT_NONCLIENT;
1449 }
1450
1451
1452 /* get a list of the window parents, up to the root of the tree */
1453 DECL_HANDLER(get_window_parents)
1454 {
1455     struct window *ptr, *win = get_window( req->handle );
1456     int total = 0;
1457     user_handle_t *data;
1458     size_t len;
1459
1460     if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
1461
1462     reply->count = total;
1463     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
1464     if (len && ((data = set_reply_data_size( len ))))
1465     {
1466         for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
1467             *data++ = ptr->handle;
1468     }
1469 }
1470
1471
1472 /* get a list of the window children */
1473 DECL_HANDLER(get_window_children)
1474 {
1475     struct window *ptr, *parent = get_window( req->parent );
1476     int total = 0;
1477     user_handle_t *data;
1478     size_t len;
1479
1480     if (parent)
1481     {
1482         LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
1483         {
1484             if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
1485             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
1486             total++;
1487         }
1488     }
1489     reply->count = total;
1490     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
1491     if (len && ((data = set_reply_data_size( len ))))
1492     {
1493         LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
1494         {
1495             if (len < sizeof(*data)) break;
1496             if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
1497             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
1498             *data++ = ptr->handle;
1499             len -= sizeof(*data);
1500         }
1501     }
1502 }
1503
1504
1505 /* get a list of the window children that contain a given point */
1506 DECL_HANDLER(get_window_children_from_point)
1507 {
1508     struct user_handle_array array;
1509     struct window *parent = get_window( req->parent );
1510     size_t len;
1511
1512     if (!parent) return;
1513
1514     array.handles = NULL;
1515     array.count = 0;
1516     array.total = 0;
1517     if (!all_windows_from_point( parent, req->x, req->y, &array )) return;
1518
1519     reply->count = array.count;
1520     len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) );
1521     if (len) set_reply_data_ptr( array.handles, len );
1522     else free( array.handles );
1523 }
1524
1525
1526 /* get window tree information from a window handle */
1527 DECL_HANDLER(get_window_tree)
1528 {
1529     struct window *ptr, *win = get_window( req->handle );
1530
1531     if (!win) return;
1532
1533     reply->parent        = 0;
1534     reply->owner         = 0;
1535     reply->next_sibling  = 0;
1536     reply->prev_sibling  = 0;
1537     reply->first_sibling = 0;
1538     reply->last_sibling  = 0;
1539     reply->first_child   = 0;
1540     reply->last_child    = 0;
1541
1542     if (win->parent)
1543     {
1544         struct window *parent = win->parent;
1545         reply->parent = parent->handle;
1546         reply->owner  = win->owner;
1547         if ((ptr = get_next_window( win ))) reply->next_sibling = ptr->handle;
1548         if ((ptr = get_prev_window( win ))) reply->prev_sibling = ptr->handle;
1549         if ((ptr = get_first_child( parent ))) reply->first_sibling = ptr->handle;
1550         if ((ptr = get_last_child( parent ))) reply->last_sibling = ptr->handle;
1551     }
1552     if ((ptr = get_first_child( win ))) reply->first_child = ptr->handle;
1553     if ((ptr = get_last_child( win ))) reply->last_child = ptr->handle;
1554 }
1555
1556
1557 /* set the position and Z order of a window */
1558 DECL_HANDLER(set_window_pos)
1559 {
1560     const rectangle_t *visible_rect = NULL, *valid_rects = NULL;
1561     struct window *previous = NULL;
1562     struct window *win = get_window( req->handle );
1563     unsigned int flags = req->flags;
1564
1565     if (!win) return;
1566     if (!win->parent) flags |= SWP_NOZORDER;  /* no Z order for the desktop */
1567
1568     if (!(flags & SWP_NOZORDER))
1569     {
1570         if (!req->previous)  /* special case: HWND_TOP */
1571         {
1572             if (get_first_child(win->parent) == win) flags |= SWP_NOZORDER;
1573         }
1574         else if (req->previous == (user_handle_t)1)  /* special case: HWND_BOTTOM */
1575         {
1576             previous = get_last_child( win->parent );
1577         }
1578         else
1579         {
1580             if (!(previous = get_window( req->previous ))) return;
1581             /* previous must be a sibling */
1582             if (previous->parent != win->parent)
1583             {
1584                 set_error( STATUS_INVALID_PARAMETER );
1585                 return;
1586             }
1587         }
1588         if (previous == win) flags |= SWP_NOZORDER;  /* nothing to do */
1589     }
1590
1591     /* window rectangle must be ordered properly */
1592     if (req->window.right < req->window.left || req->window.bottom < req->window.top)
1593     {
1594         set_error( STATUS_INVALID_PARAMETER );
1595         return;
1596     }
1597
1598     if (get_req_data_size() >= sizeof(rectangle_t)) visible_rect = get_req_data();
1599     if (get_req_data_size() >= 3 * sizeof(rectangle_t)) valid_rects = visible_rect + 1;
1600
1601     if (!visible_rect) visible_rect = &req->window;
1602     set_window_pos( win, previous, flags, &req->window, &req->client, visible_rect, valid_rects );
1603     reply->new_style = win->style;
1604 }
1605
1606
1607 /* get the window and client rectangles of a window */
1608 DECL_HANDLER(get_window_rectangles)
1609 {
1610     struct window *win = get_window( req->handle );
1611
1612     if (win)
1613     {
1614         reply->window  = win->window_rect;
1615         reply->visible = win->visible_rect;
1616         reply->client  = win->client_rect;
1617     }
1618 }
1619
1620
1621 /* get the window text */
1622 DECL_HANDLER(get_window_text)
1623 {
1624     struct window *win = get_window( req->handle );
1625
1626     if (win && win->text)
1627     {
1628         size_t len = strlenW( win->text ) * sizeof(WCHAR);
1629         if (len > get_reply_max_size()) len = get_reply_max_size();
1630         set_reply_data( win->text, len );
1631     }
1632 }
1633
1634
1635 /* set the window text */
1636 DECL_HANDLER(set_window_text)
1637 {
1638     struct window *win = get_window( req->handle );
1639
1640     if (win)
1641     {
1642         WCHAR *text = NULL;
1643         size_t len = get_req_data_size() / sizeof(WCHAR);
1644         if (len)
1645         {
1646             if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) return;
1647             memcpy( text, get_req_data(), len * sizeof(WCHAR) );
1648             text[len] = 0;
1649         }
1650         if (win->text) free( win->text );
1651         win->text = text;
1652     }
1653 }
1654
1655
1656 /* get the coordinates offset between two windows */
1657 DECL_HANDLER(get_windows_offset)
1658 {
1659     struct window *win;
1660
1661     reply->x = reply->y = 0;
1662     if (req->from)
1663     {
1664         if (!(win = get_window( req->from ))) return;
1665         while (win)
1666         {
1667             reply->x += win->client_rect.left;
1668             reply->y += win->client_rect.top;
1669             win = win->parent;
1670         }
1671     }
1672     if (req->to)
1673     {
1674         if (!(win = get_window( req->to ))) return;
1675         while (win)
1676         {
1677             reply->x -= win->client_rect.left;
1678             reply->y -= win->client_rect.top;
1679             win = win->parent;
1680         }
1681     }
1682 }
1683
1684
1685 /* get the visible region of a window */
1686 DECL_HANDLER(get_visible_region)
1687 {
1688     struct region *region;
1689     struct window *top, *win = get_window( req->window );
1690
1691     if (!win) return;
1692
1693     top = get_top_clipping_window( win );
1694     if ((region = get_visible_region( win, top, req->flags )))
1695     {
1696         rectangle_t *data;
1697         map_win_region_to_screen( win, region );
1698         data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size );
1699         if (data) set_reply_data_ptr( data, reply->total_size );
1700     }
1701     reply->top_win   = top->handle;
1702     reply->top_org_x = top->visible_rect.left;
1703     reply->top_org_y = top->visible_rect.top;
1704     reply->win_org_x = (req->flags & DCX_WINDOW) ? win->window_rect.left : win->client_rect.left;
1705     reply->win_org_y = (req->flags & DCX_WINDOW) ? win->window_rect.top : win->client_rect.top;
1706     client_to_screen( top->parent, &reply->top_org_x, &reply->top_org_y );
1707     client_to_screen( win->parent, &reply->win_org_x, &reply->win_org_y );
1708 }
1709
1710
1711 /* get the window region */
1712 DECL_HANDLER(get_window_region)
1713 {
1714     struct window *win = get_window( req->window );
1715
1716     if (!win) return;
1717
1718     if (win->win_region)
1719     {
1720         rectangle_t *data = get_region_data( win->win_region, get_reply_max_size(), &reply->total_size );
1721         if (data) set_reply_data_ptr( data, reply->total_size );
1722     }
1723 }
1724
1725
1726 /* set the window region */
1727 DECL_HANDLER(set_window_region)
1728 {
1729     struct region *region = NULL;
1730     struct window *win = get_window( req->window );
1731
1732     if (!win) return;
1733
1734     if (get_req_data_size())  /* no data means remove the region completely */
1735     {
1736         if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
1737             return;
1738     }
1739     if (win->win_region) free_region( win->win_region );
1740     win->win_region = region;
1741 }
1742
1743
1744 /* get a window update region */
1745 DECL_HANDLER(get_update_region)
1746 {
1747     rectangle_t *data;
1748     unsigned int flags = req->flags;
1749     struct window *from_child = NULL;
1750     struct window *win = get_window( req->window );
1751
1752     reply->flags = 0;
1753     if (!win) return;
1754
1755     if (req->from_child)
1756     {
1757         struct window *ptr;
1758
1759         if (!(from_child = get_window( req->from_child ))) return;
1760
1761         /* make sure from_child is a child of win */
1762         ptr = from_child;
1763         while (ptr && ptr != win) ptr = ptr->parent;
1764         if (!ptr)
1765         {
1766             set_error( STATUS_INVALID_PARAMETER );
1767             return;
1768         }
1769     }
1770
1771     reply->flags = get_window_update_flags( win, from_child, flags, &win );
1772     reply->child = win->handle;
1773
1774     if (flags & UPDATE_NOREGION) return;
1775
1776     if (win->update_region)
1777     {
1778         /* convert update region to screen coordinates */
1779         struct region *region = create_empty_region();
1780
1781         if (!region) return;
1782         if (!copy_region( region, win->update_region ))
1783         {
1784             free_region( region );
1785             return;
1786         }
1787         map_win_region_to_screen( win, region );
1788         if (!(data = get_region_data_and_free( region, get_reply_max_size(),
1789                                                &reply->total_size ))) return;
1790         set_reply_data_ptr( data, reply->total_size );
1791     }
1792
1793     if (reply->flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT)) /* validate everything */
1794     {
1795         validate_whole_window( win );
1796     }
1797     else
1798     {
1799         if (reply->flags & UPDATE_NONCLIENT) validate_non_client( win );
1800         if (reply->flags & UPDATE_ERASE)
1801         {
1802             win->paint_flags &= ~PAINT_ERASE;
1803             /* desktop window only gets erased, not repainted */
1804             if (win == top_window) validate_whole_window( win );
1805         }
1806     }
1807 }
1808
1809
1810 /* update the z order of a window so that a given rectangle is fully visible */
1811 DECL_HANDLER(update_window_zorder)
1812 {
1813     rectangle_t tmp;
1814     struct window *ptr, *win = get_window( req->window );
1815
1816     if (!win || !win->parent || !is_visible( win )) return;  /* nothing to do */
1817
1818     LIST_FOR_EACH_ENTRY( ptr, &win->parent->children, struct window, entry )
1819     {
1820         if (ptr == win) break;
1821         if (!(ptr->style & WS_VISIBLE)) continue;
1822         if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
1823         if (!intersect_rect( &tmp, &ptr->visible_rect, &req->rect )) continue;
1824         if (ptr->win_region && !rect_in_region( ptr->win_region, &req->rect )) continue;
1825         /* found a window obscuring the rectangle, now move win above this one */
1826         list_remove( &win->entry );
1827         list_add_before( &ptr->entry, &win->entry );
1828         break;
1829     }
1830 }
1831
1832
1833 /* mark parts of a window as needing a redraw */
1834 DECL_HANDLER(redraw_window)
1835 {
1836     struct region *region = NULL;
1837     struct window *win = get_window( req->window );
1838
1839     if (!win) return;
1840     if (!is_visible( win )) return;  /* nothing to do */
1841
1842     if (req->flags & (RDW_VALIDATE|RDW_INVALIDATE))
1843     {
1844         if (get_req_data_size())  /* no data means whole rectangle */
1845         {
1846             if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
1847                 return;
1848         }
1849     }
1850
1851     redraw_window( win, region, (req->flags & RDW_INVALIDATE) && (req->flags & RDW_FRAME),
1852                    req->flags );
1853     if (region) free_region( region );
1854 }
1855
1856
1857 /* set a window property */
1858 DECL_HANDLER(set_window_property)
1859 {
1860     struct window *win = get_window( req->window );
1861
1862     if (!win) return;
1863
1864     if (get_req_data_size())
1865     {
1866         atom_t atom = add_global_atom( get_req_data(), get_req_data_size() / sizeof(WCHAR) );
1867         if (atom)
1868         {
1869             set_property( win, atom, req->handle, PROP_TYPE_STRING );
1870             release_global_atom( atom );
1871         }
1872     }
1873     else set_property( win, req->atom, req->handle, PROP_TYPE_ATOM );
1874 }
1875
1876
1877 /* remove a window property */
1878 DECL_HANDLER(remove_window_property)
1879 {
1880     struct window *win = get_window( req->window );
1881     reply->handle = 0;
1882     if (win)
1883     {
1884         atom_t atom = req->atom;
1885         if (get_req_data_size()) atom = find_global_atom( get_req_data(),
1886                                                           get_req_data_size() / sizeof(WCHAR) );
1887         if (atom) reply->handle = remove_property( win, atom );
1888     }
1889 }
1890
1891
1892 /* get a window property */
1893 DECL_HANDLER(get_window_property)
1894 {
1895     struct window *win = get_window( req->window );
1896     reply->handle = 0;
1897     if (win)
1898     {
1899         atom_t atom = req->atom;
1900         if (get_req_data_size()) atom = find_global_atom( get_req_data(),
1901                                                           get_req_data_size() / sizeof(WCHAR) );
1902         if (atom) reply->handle = get_property( win, atom );
1903     }
1904 }
1905
1906
1907 /* get the list of properties of a window */
1908 DECL_HANDLER(get_window_properties)
1909 {
1910     property_data_t *data;
1911     int i, count, max = get_reply_max_size() / sizeof(*data);
1912     struct window *win = get_window( req->window );
1913
1914     reply->total = 0;
1915     if (!win) return;
1916
1917     for (i = count = 0; i < win->prop_inuse; i++)
1918         if (win->properties[i].type != PROP_TYPE_FREE) count++;
1919     reply->total = count;
1920
1921     if (count > max) count = max;
1922     if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) return;
1923
1924     for (i = 0; i < win->prop_inuse && count; i++)
1925     {
1926         if (win->properties[i].type == PROP_TYPE_FREE) continue;
1927         data->atom   = win->properties[i].atom;
1928         data->string = (win->properties[i].type == PROP_TYPE_STRING);
1929         data->handle = win->properties[i].handle;
1930         data++;
1931         count--;
1932     }
1933 }
1934
1935
1936 /* get the new window pointer for a global window, checking permissions */
1937 /* helper for set_global_windows request */
1938 static int get_new_global_window( struct window **win, user_handle_t handle )
1939 {
1940     if (!handle)
1941     {
1942         *win = NULL;
1943         return 1;
1944     }
1945     else if (*win)
1946     {
1947         set_error( STATUS_ACCESS_DENIED );
1948         return 0;
1949     }
1950     *win = get_window( handle );
1951     return (*win != NULL);
1952 }
1953
1954 /* Set/get the global windows */
1955 DECL_HANDLER(set_global_windows)
1956 {
1957     struct window *new_shell_window   = shell_window;
1958     struct window *new_shell_listview = shell_listview;
1959     struct window *new_progman_window = progman_window;
1960     struct window *new_taskman_window = taskman_window;
1961
1962     reply->old_shell_window   = shell_window ? shell_window->handle : 0;
1963     reply->old_shell_listview = shell_listview ? shell_listview->handle : 0;
1964     reply->old_progman_window = progman_window ? progman_window->handle : 0;
1965     reply->old_taskman_window = taskman_window ? taskman_window->handle : 0;
1966
1967     if (req->flags & SET_GLOBAL_SHELL_WINDOWS)
1968     {
1969         if (!get_new_global_window( &new_shell_window, req->shell_window )) return;
1970         if (!get_new_global_window( &new_shell_listview, req->shell_listview )) return;
1971     }
1972     if (req->flags & SET_GLOBAL_PROGMAN_WINDOW)
1973     {
1974         if (!get_new_global_window( &new_progman_window, req->progman_window )) return;
1975     }
1976     if (req->flags & SET_GLOBAL_TASKMAN_WINDOW)
1977     {
1978         if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return;
1979     }
1980     shell_window   = new_shell_window;
1981     shell_listview = new_shell_listview;
1982     progman_window = new_progman_window;
1983     taskman_window = new_taskman_window;
1984 }