Make init_thread request deal better with fd allocation errors.
[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     atom_t           atom;            /* class atom */
67     user_handle_t    last_active;     /* last active popup */
68     rectangle_t      window_rect;     /* window rectangle */
69     rectangle_t      client_rect;     /* client rectangle */
70     unsigned int     style;           /* window style */
71     unsigned int     ex_style;        /* window extended style */
72     unsigned int     id;              /* window id */
73     void*            instance;        /* creator instance */
74     void*            user_data;       /* user-specific data */
75     WCHAR           *text;            /* window caption text */
76     int              paint_count;     /* count of pending paints for this window */
77     int              prop_inuse;      /* number of in-use window properties */
78     int              prop_alloc;      /* number of allocated window properties */
79     struct property *properties;      /* window properties array */
80 };
81
82 static struct window *top_window;  /* top-level (desktop) window */
83
84 /* global window pointers */
85 static struct window *shell_window;
86 static struct window *shell_listview;
87 static struct window *progman_window;
88 static struct window *taskman_window;
89
90 /* retrieve a pointer to a window from its handle */
91 inline static struct window *get_window( user_handle_t handle )
92 {
93     struct window *ret = get_user_object( handle, USER_WINDOW );
94     if (!ret) set_error( STATUS_INVALID_HANDLE );
95     return ret;
96 }
97
98 /* unlink a window from the tree */
99 static void unlink_window( struct window *win )
100 {
101     struct window *parent = win->parent;
102
103     assert( parent );
104
105     if (win->next) win->next->prev = win->prev;
106     else if (parent->last_child == win) parent->last_child = win->prev;
107
108     if (win->prev) win->prev->next = win->next;
109     else if (parent->first_child == win) parent->first_child = win->next;
110     else if (parent->first_unlinked == win) parent->first_unlinked = win->next;
111 }
112
113
114 /* link a window into the tree (or unlink it if the new parent is NULL)  */
115 static void link_window( struct window *win, struct window *parent, struct window *previous )
116 {
117     unlink_window( win );  /* unlink it from the previous location */
118
119     if (parent)
120     {
121         win->parent = parent;
122         if ((win->prev = previous))
123         {
124             if ((win->next = previous->next)) win->next->prev = win;
125             else if (win->parent->last_child == previous) win->parent->last_child = win;
126             win->prev->next = win;
127         }
128         else
129         {
130             if ((win->next = parent->first_child)) win->next->prev = win;
131             else win->parent->last_child = win;
132             parent->first_child = win;
133         }
134     }
135     else  /* move it to parent unlinked list */
136     {
137         parent = win->parent;
138         if ((win->next = parent->first_unlinked)) win->next->prev = win;
139         win->prev = NULL;
140         parent->first_unlinked = win;
141     }
142 }
143
144 /* set a window property */
145 static void set_property( struct window *win, atom_t atom, obj_handle_t handle,
146                           enum property_type type )
147 {
148     int i, free = -1;
149     struct property *new_props;
150
151     /* check if it exists already */
152     for (i = 0; i < win->prop_inuse; i++)
153     {
154         if (win->properties[i].type == PROP_TYPE_FREE)
155         {
156             free = i;
157             continue;
158         }
159         if (win->properties[i].atom == atom)
160         {
161             win->properties[i].type = type;
162             win->properties[i].handle = handle;
163             return;
164         }
165     }
166
167     /* need to add an entry */
168     if (!grab_global_atom( atom )) return;
169     if (free == -1)
170     {
171         /* no free entry */
172         if (win->prop_inuse >= win->prop_alloc)
173         {
174             /* need to grow the array */
175             if (!(new_props = realloc( win->properties,
176                                        sizeof(*new_props) * (win->prop_alloc + 16) )))
177             {
178                 set_error( STATUS_NO_MEMORY );
179                 release_global_atom( atom );
180                 return;
181             }
182             win->prop_alloc += 16;
183             win->properties = new_props;
184         }
185         free = win->prop_inuse++;
186     }
187     win->properties[free].atom   = atom;
188     win->properties[free].type   = type;
189     win->properties[free].handle = handle;
190 }
191
192 /* remove a window property */
193 static obj_handle_t remove_property( struct window *win, atom_t atom )
194 {
195     int i;
196
197     for (i = 0; i < win->prop_inuse; i++)
198     {
199         if (win->properties[i].type == PROP_TYPE_FREE) continue;
200         if (win->properties[i].atom == atom)
201         {
202             release_global_atom( atom );
203             win->properties[i].type = PROP_TYPE_FREE;
204             return win->properties[i].handle;
205         }
206     }
207     /* FIXME: last error? */
208     return 0;
209 }
210
211 /* find a window property */
212 static obj_handle_t get_property( struct window *win, atom_t atom )
213 {
214     int i;
215
216     for (i = 0; i < win->prop_inuse; i++)
217     {
218         if (win->properties[i].type == PROP_TYPE_FREE) continue;
219         if (win->properties[i].atom == atom) return win->properties[i].handle;
220     }
221     /* FIXME: last error? */
222     return 0;
223 }
224
225 /* destroy all properties of a window */
226 inline static void destroy_properties( struct window *win )
227 {
228     int i;
229
230     if (!win->properties) return;
231     for (i = 0; i < win->prop_inuse; i++)
232     {
233         if (win->properties[i].type == PROP_TYPE_FREE) continue;
234         release_global_atom( win->properties[i].atom );
235     }
236     free( win->properties );
237 }
238
239 /* destroy a window */
240 static void destroy_window( struct window *win )
241 {
242     assert( win != top_window );
243
244     /* destroy all children */
245     while (win->first_child) destroy_window( win->first_child );
246     while (win->first_unlinked) destroy_window( win->first_unlinked );
247
248     if (win->thread->queue)
249     {
250         if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count );
251         queue_cleanup_window( win->thread, win->handle );
252     }
253     /* reset global window pointers, if the corresponding window is destroyed */
254     if (win == shell_window) shell_window = NULL;
255     if (win == shell_listview) shell_listview = NULL;
256     if (win == progman_window) progman_window = NULL;
257     if (win == taskman_window) taskman_window = NULL;
258     free_user_handle( win->handle );
259     destroy_properties( win );
260     unlink_window( win );
261     if (win->text) free( win->text );
262     memset( win, 0x55, sizeof(*win) );
263     free( win );
264 }
265
266 /* create a new window structure (note: the window is not linked in the window tree) */
267 static struct window *create_window( struct window *parent, struct window *owner, atom_t atom )
268 {
269     struct window *win = mem_alloc( sizeof(*win) );
270     if (!win) return NULL;
271
272     if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
273     {
274         free( win );
275         return NULL;
276     }
277     win->parent         = parent;
278     win->owner          = owner ? owner->handle : 0;
279     win->first_child    = NULL;
280     win->last_child     = NULL;
281     win->first_unlinked = NULL;
282     win->thread         = current;
283     win->atom           = atom;
284     win->last_active    = win->handle;
285     win->style          = 0;
286     win->ex_style       = 0;
287     win->id             = 0;
288     win->instance       = NULL;
289     win->user_data      = NULL;
290     win->text           = NULL;
291     win->paint_count    = 0;
292     win->prop_inuse     = 0;
293     win->prop_alloc     = 0;
294     win->properties     = NULL;
295
296     if (parent)  /* put it on parent unlinked list */
297     {
298         if ((win->next = parent->first_unlinked)) win->next->prev = win;
299         win->prev = NULL;
300         parent->first_unlinked = win;
301     }
302     else win->next = win->prev = NULL;
303
304     /* if parent belongs to a different thread, attach the two threads */
305     if (parent && parent->thread && parent->thread != current)
306         attach_thread_input( current, parent->thread );
307     return win;
308 }
309
310 /* destroy all windows belonging to a given thread */
311 void destroy_thread_windows( struct thread *thread )
312 {
313     user_handle_t handle = 0;
314     struct window *win;
315
316     while ((win = next_user_handle( &handle, USER_WINDOW )))
317     {
318         if (win->thread != thread) continue;
319         destroy_window( win );
320     }
321 }
322
323 /* check whether child is a descendant of parent */
324 int is_child_window( user_handle_t parent, user_handle_t child )
325 {
326     struct window *child_ptr = get_user_object( child, USER_WINDOW );
327     struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
328
329     if (!child_ptr || !parent_ptr) return 0;
330     while (child_ptr->parent)
331     {
332         if (child_ptr->parent == parent_ptr) return 1;
333         child_ptr = child_ptr->parent;
334     }
335     return 0;
336 }
337
338 /* check whether window is a top-level window */
339 int is_top_level_window( user_handle_t window )
340 {
341     struct window *win = get_user_object( window, USER_WINDOW );
342     return (win && win->parent == top_window);
343 }
344
345 /* make a window active if possible */
346 int make_window_active( user_handle_t window )
347 {
348     struct window *owner, *win = get_window( window );
349
350     if (!win) return 0;
351
352     /* set last active for window and its owner */
353     win->last_active = win->handle;
354     if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
355     return 1;
356 }
357
358 /* find child of 'parent' that contains the given point (in parent-relative coords) */
359 static struct window *child_window_from_point( struct window *parent, int x, int y )
360 {
361     struct window *ptr;
362
363     for (ptr = parent->first_child; ptr; ptr = ptr->next)
364     {
365         if (!(ptr->style & WS_VISIBLE)) continue; /* not visible -> skip */
366         if ((ptr->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
367             continue;  /* disabled child -> skip */
368         if ((ptr->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
369             continue;  /* transparent -> skip */
370         if (x < ptr->window_rect.left || x >= ptr->window_rect.right ||
371             y < ptr->window_rect.top || y >= ptr->window_rect.bottom)
372             continue;  /* not in window -> skip */
373
374         /* FIXME: check window region here */
375
376         /* if window is minimized or disabled, return at once */
377         if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
378
379         /* if point is not in client area, return at once */
380         if (x < ptr->client_rect.left || x >= ptr->client_rect.right ||
381             y < ptr->client_rect.top || y >= ptr->client_rect.bottom)
382             return ptr;
383
384         return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top );
385     }
386     return parent;  /* not found any child */
387 }
388
389 /* find window containing point (in absolute coords) */
390 user_handle_t window_from_point( int x, int y )
391 {
392     struct window *ret;
393
394     if (!top_window) return 0;
395     ret = child_window_from_point( top_window, x, y );
396     return ret->handle;
397 }
398
399 /* return the thread owning a window */
400 struct thread *get_window_thread( user_handle_t handle )
401 {
402     struct window *win = get_user_object( handle, USER_WINDOW );
403     if (!win || !win->thread) return NULL;
404     return (struct thread *)grab_object( win->thread );
405 }
406
407 /* find a child of the specified window that needs repainting */
408 static struct window *find_child_to_repaint( struct window *parent, struct thread *thread )
409 {
410     struct window *ptr, *ret = NULL;
411
412     for (ptr = parent->first_child; ptr && !ret; ptr = ptr->next)
413     {
414         if (!(ptr->style & WS_VISIBLE)) continue;
415         if (ptr->paint_count && ptr->thread == thread)
416             ret = ptr;
417         else /* explore its children */
418             ret = find_child_to_repaint( ptr, thread );
419     }
420
421     if (ret && (ret->ex_style & WS_EX_TRANSPARENT))
422     {
423         /* transparent window, check for non-transparent sibling to paint first */
424         for (ptr = ret->next; ptr; ptr = ptr->next)
425         {
426             if (!(ptr->style & WS_VISIBLE)) continue;
427             if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
428             if (ptr->paint_count && ptr->thread == thread) return ptr;
429         }
430     }
431     return ret;
432 }
433
434
435 /* find a window that needs repainting */
436 user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread )
437 {
438     struct window *win = parent ? get_window( parent ) : top_window;
439
440     if (!win || !(win->style & WS_VISIBLE)) return 0;
441     if (!win->paint_count || win->thread != thread)
442         win = find_child_to_repaint( win, thread );
443     return win ? win->handle : 0;
444 }
445
446
447 /* create a window */
448 DECL_HANDLER(create_window)
449 {
450     reply->handle = 0;
451     if (!req->parent)  /* return desktop window */
452     {
453         if (!top_window)
454         {
455             if (!(top_window = create_window( NULL, NULL, req->atom ))) return;
456             top_window->thread = NULL;  /* no thread owns the desktop */
457             top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
458         }
459         reply->handle = top_window->handle;
460     }
461     else
462     {
463         struct window *win, *parent, *owner = NULL;
464
465         if (!(parent = get_window( req->parent ))) return;
466         if (req->owner && !(owner = get_window( req->owner ))) return;
467         if (owner == top_window) owner = NULL;
468         else if (owner && parent != top_window)
469         {
470             /* an owned window must be created as top-level */
471             set_error( STATUS_ACCESS_DENIED );
472             return;
473         }
474         if (!(win = create_window( parent, owner, req->atom ))) return;
475         reply->handle = win->handle;
476     }
477 }
478
479
480 /* link a window into the tree */
481 DECL_HANDLER(link_window)
482 {
483     struct window *win, *parent = NULL, *previous = NULL;
484
485     if (!(win = get_window( req->handle ))) return;
486     if (req->parent && !(parent = get_window( req->parent ))) return;
487
488     if (win == top_window)
489     {
490         set_error( STATUS_INVALID_PARAMETER );
491         return;
492     }
493     reply->full_parent = parent ? parent->handle : 0;
494     if (parent && req->previous)
495     {
496         if (req->previous == (user_handle_t)1)  /* special case: HWND_BOTTOM */
497         {
498             previous = parent->last_child;
499             if (previous == win) return;  /* nothing to do */
500         }
501         else
502         {
503             if (!(previous = get_window( req->previous ))) return;
504             /* previous must be a child of parent, and not win itself */
505             if (previous->parent != parent || previous == win)
506             {
507                 set_error( STATUS_INVALID_PARAMETER );
508                 return;
509             }
510         }
511     }
512     link_window( win, parent, previous );
513 }
514
515
516 /* destroy a window */
517 DECL_HANDLER(destroy_window)
518 {
519     struct window *win = get_window( req->handle );
520     if (win)
521     {
522         if (win != top_window) destroy_window( win );
523         else set_error( STATUS_ACCESS_DENIED );
524     }
525 }
526
527
528 /* set a window owner */
529 DECL_HANDLER(set_window_owner)
530 {
531     struct window *win = get_window( req->handle );
532     struct window *owner = NULL;
533
534     if (!win) return;
535     if (req->owner && !(owner = get_window( req->owner ))) return;
536     if (win == top_window)
537     {
538         set_error( STATUS_ACCESS_DENIED );
539         return;
540     }
541     reply->prev_owner = win->owner;
542     reply->full_owner = win->owner = owner ? owner->handle : 0;
543 }
544
545
546 /* get information from a window handle */
547 DECL_HANDLER(get_window_info)
548 {
549     struct window *win = get_window( req->handle );
550
551     reply->full_handle = 0;
552     reply->tid = reply->pid = 0;
553     if (win)
554     {
555         reply->full_handle = win->handle;
556         reply->last_active = win->handle;
557         if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active;
558         if (win->thread)
559         {
560             reply->tid  = get_thread_id( win->thread );
561             reply->pid  = get_process_id( win->thread->process );
562             reply->atom = win->atom;
563         }
564     }
565 }
566
567
568 /* set some information in a window */
569 DECL_HANDLER(set_window_info)
570 {
571     struct window *win = get_window( req->handle );
572
573     if (!win) return;
574     if (req->flags && win == top_window)
575     {
576         set_error( STATUS_ACCESS_DENIED );
577         return;
578     }
579     reply->old_style     = win->style;
580     reply->old_ex_style  = win->ex_style;
581     reply->old_id        = win->id;
582     reply->old_instance  = win->instance;
583     reply->old_user_data = win->user_data;
584     if (req->flags & SET_WIN_STYLE) win->style = req->style;
585     if (req->flags & SET_WIN_EXSTYLE) win->ex_style = req->ex_style;
586     if (req->flags & SET_WIN_ID) win->id = req->id;
587     if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance;
588     if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data;
589 }
590
591
592 /* get a list of the window parents, up to the root of the tree */
593 DECL_HANDLER(get_window_parents)
594 {
595     struct window *ptr, *win = get_window( req->handle );
596     int total = 0;
597     user_handle_t *data;
598     size_t len;
599
600     if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
601
602     reply->count = total;
603     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
604     if (len && ((data = set_reply_data_size( len ))))
605     {
606         for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
607             *data++ = ptr->handle;
608     }
609 }
610
611
612 /* get a list of the window children */
613 DECL_HANDLER(get_window_children)
614 {
615     struct window *ptr, *parent = get_window( req->parent );
616     int total = 0;
617     user_handle_t *data;
618     size_t len;
619
620     if (parent)
621         for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next)
622         {
623             if (req->atom && ptr->atom != req->atom) continue;
624             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
625             total++;
626         }
627
628     reply->count = total;
629     len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
630     if (len && ((data = set_reply_data_size( len ))))
631     {
632         for (ptr = parent->first_child; ptr && len; ptr = ptr->next)
633         {
634             if (req->atom && ptr->atom != req->atom) continue;
635             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
636             *data++ = ptr->handle;
637             len -= sizeof(*data);
638         }
639     }
640 }
641
642
643 /* get window tree information from a window handle */
644 DECL_HANDLER(get_window_tree)
645 {
646     struct window *win = get_window( req->handle );
647
648     if (!win) return;
649
650     if (win->parent)
651     {
652         struct window *parent = win->parent;
653         reply->parent        = parent->handle;
654         reply->owner         = win->owner;
655         reply->next_sibling  = win->next ? win->next->handle : 0;
656         reply->prev_sibling  = win->prev ? win->prev->handle : 0;
657         reply->first_sibling = parent->first_child ? parent->first_child->handle : 0;
658         reply->last_sibling  = parent->last_child ? parent->last_child->handle : 0;
659     }
660     else
661     {
662         reply->parent        = 0;
663         reply->owner         = 0;
664         reply->next_sibling  = 0;
665         reply->prev_sibling  = 0;
666         reply->first_sibling = 0;
667         reply->last_sibling  = 0;
668     }
669     reply->first_child = win->first_child ? win->first_child->handle : 0;
670     reply->last_child  = win->last_child ? win->last_child->handle : 0;
671 }
672
673
674 /* set the window and client rectangles of a window */
675 DECL_HANDLER(set_window_rectangles)
676 {
677     struct window *win = get_window( req->handle );
678
679     if (win)
680     {
681         win->window_rect = req->window;
682         win->client_rect = req->client;
683     }
684 }
685
686
687 /* get the window and client rectangles of a window */
688 DECL_HANDLER(get_window_rectangles)
689 {
690     struct window *win = get_window( req->handle );
691
692     if (win)
693     {
694         reply->window = win->window_rect;
695         reply->client = win->client_rect;
696     }
697 }
698
699
700 /* get the window text */
701 DECL_HANDLER(get_window_text)
702 {
703     struct window *win = get_window( req->handle );
704
705     if (win && win->text)
706     {
707         size_t len = strlenW( win->text ) * sizeof(WCHAR);
708         if (len > get_reply_max_size()) len = get_reply_max_size();
709         set_reply_data( win->text, len );
710     }
711 }
712
713
714 /* set the window text */
715 DECL_HANDLER(set_window_text)
716 {
717     struct window *win = get_window( req->handle );
718
719     if (win)
720     {
721         WCHAR *text = NULL;
722         size_t len = get_req_data_size() / sizeof(WCHAR);
723         if (len)
724         {
725             if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) return;
726             memcpy( text, get_req_data(), len * sizeof(WCHAR) );
727             text[len] = 0;
728         }
729         if (win->text) free( win->text );
730         win->text = text;
731     }
732 }
733
734
735 /* increment the window paint count */
736 DECL_HANDLER(inc_window_paint_count)
737 {
738     struct window *win = get_window( req->handle );
739
740     if (win && win->thread)
741     {
742         int old = win->paint_count;
743         if ((win->paint_count += req->incr) < 0) win->paint_count = 0;
744         inc_queue_paint_count( win->thread, win->paint_count - old );
745     }
746 }
747
748
749 /* get the coordinates offset between two windows */
750 DECL_HANDLER(get_windows_offset)
751 {
752     struct window *win;
753
754     reply->x = reply->y = 0;
755     if (req->from)
756     {
757         if (!(win = get_window( req->from ))) return;
758         while (win)
759         {
760             reply->x += win->client_rect.left;
761             reply->y += win->client_rect.top;
762             win = win->parent;
763         }
764     }
765     if (req->to)
766     {
767         if (!(win = get_window( req->to ))) return;
768         while (win)
769         {
770             reply->x -= win->client_rect.left;
771             reply->y -= win->client_rect.top;
772             win = win->parent;
773         }
774     }
775 }
776
777
778 /* set a window property */
779 DECL_HANDLER(set_window_property)
780 {
781     struct window *win = get_window( req->window );
782
783     if (win) set_property( win, req->atom, req->handle,
784                            req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM );
785 }
786
787
788 /* remove a window property */
789 DECL_HANDLER(remove_window_property)
790 {
791     struct window *win = get_window( req->window );
792     reply->handle = 0;
793     if (win) reply->handle = remove_property( win, req->atom );
794 }
795
796
797 /* get a window property */
798 DECL_HANDLER(get_window_property)
799 {
800     struct window *win = get_window( req->window );
801     reply->handle = 0;
802     if (win) reply->handle = get_property( win, req->atom );
803 }
804
805
806 /* get the list of properties of a window */
807 DECL_HANDLER(get_window_properties)
808 {
809     property_data_t *data;
810     int i, count, max = get_reply_max_size() / sizeof(*data);
811     struct window *win = get_window( req->window );
812
813     reply->total = 0;
814     if (!win) return;
815
816     for (i = count = 0; i < win->prop_inuse; i++)
817         if (win->properties[i].type != PROP_TYPE_FREE) count++;
818     reply->total = count;
819
820     if (count > max) count = max;
821     if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) return;
822
823     for (i = 0; i < win->prop_inuse && count; i++)
824     {
825         if (win->properties[i].type == PROP_TYPE_FREE) continue;
826         data->atom   = win->properties[i].atom;
827         data->string = (win->properties[i].type == PROP_TYPE_STRING);
828         data->handle = win->properties[i].handle;
829         data++;
830         count--;
831     }
832 }
833
834
835 /* get the new window pointer for a global window, checking permissions */
836 /* helper for set_global_windows request */
837 static int get_new_global_window( struct window **win, user_handle_t handle )
838 {
839     if (*win && (*win)->thread != current)
840     {
841         set_error( STATUS_ACCESS_DENIED );
842         return 0;
843     }
844     if (!handle)
845     {
846         *win = NULL;
847         return 1;
848     }
849     *win = get_window( handle );
850     return (*win != NULL);
851 }
852
853 /* Set/get the global windows */
854 DECL_HANDLER(set_global_windows)
855 {
856     struct window *new_shell_window   = shell_window;
857     struct window *new_shell_listview = shell_listview;
858     struct window *new_progman_window = progman_window;
859     struct window *new_taskman_window = taskman_window;
860
861     reply->old_shell_window   = shell_window ? shell_window->handle : 0;
862     reply->old_shell_listview = shell_listview ? shell_listview->handle : 0;
863     reply->old_progman_window = progman_window ? progman_window->handle : 0;
864     reply->old_taskman_window = taskman_window ? taskman_window->handle : 0;
865
866     if (req->flags & SET_GLOBAL_SHELL_WINDOWS)
867     {
868         if (!get_new_global_window( &new_shell_window, req->shell_window )) return;
869         if (!get_new_global_window( &new_shell_listview, req->shell_listview )) return;
870     }
871     if (req->flags & SET_GLOBAL_PROGMAN_WINDOW)
872     {
873         if (!get_new_global_window( &new_progman_window, req->progman_window )) return;
874     }
875     if (req->flags & SET_GLOBAL_TASKMAN_WINDOW)
876     {
877         if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return;
878     }
879     shell_window   = new_shell_window;
880     shell_listview = new_shell_listview;
881     progman_window = new_progman_window;
882     taskman_window = new_taskman_window;
883 }