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