2 * Server-side window handling
4 * Copyright (C) 2001 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
37 /* a window property */
40 unsigned short type
; /* property type (see below) */
41 atom_t atom
; /* property atom */
42 obj_handle_t handle
; /* property handle (user-defined storage) */
47 PROP_TYPE_FREE
, /* free entry */
48 PROP_TYPE_STRING
, /* atom that was originally a string */
49 PROP_TYPE_ATOM
/* plain atom */
55 struct window
*parent
; /* parent window */
56 user_handle_t owner
; /* owner of this window */
57 struct window
*first_child
; /* first child in Z-order */
58 struct window
*last_child
; /* last child in Z-order */
59 struct window
*first_unlinked
; /* first child not linked in the Z-order list */
60 struct window
*next
; /* next window in Z-order */
61 struct window
*prev
; /* prev window in Z-order */
62 user_handle_t handle
; /* full handle for this window */
63 struct thread
*thread
; /* thread owning the window */
64 atom_t atom
; /* class atom */
65 user_handle_t last_active
; /* last active popup */
66 rectangle_t window_rect
; /* window rectangle */
67 rectangle_t client_rect
; /* client rectangle */
68 unsigned int style
; /* window style */
69 unsigned int ex_style
; /* window extended style */
70 unsigned int id
; /* window id */
71 void* instance
; /* creator instance */
72 void* user_data
; /* user-specific data */
73 WCHAR
*text
; /* window caption text */
74 int paint_count
; /* count of pending paints for this window */
75 int prop_inuse
; /* number of in-use window properties */
76 int prop_alloc
; /* number of allocated window properties */
77 struct property
*properties
; /* window properties array */
80 static struct window
*top_window
; /* top-level (desktop) window */
83 /* retrieve a pointer to a window from its handle */
84 inline static struct window
*get_window( user_handle_t handle
)
86 struct window
*ret
= get_user_object( handle
, USER_WINDOW
);
87 if (!ret
) set_error( STATUS_INVALID_HANDLE
);
91 /* unlink a window from the tree */
92 static void unlink_window( struct window
*win
)
94 struct window
*parent
= win
->parent
;
98 if (win
->next
) win
->next
->prev
= win
->prev
;
99 else if (parent
->last_child
== win
) parent
->last_child
= win
->prev
;
101 if (win
->prev
) win
->prev
->next
= win
->next
;
102 else if (parent
->first_child
== win
) parent
->first_child
= win
->next
;
103 else if (parent
->first_unlinked
== win
) parent
->first_unlinked
= win
->next
;
107 /* link a window into the tree (or unlink it if the new parent is NULL) */
108 static void link_window( struct window
*win
, struct window
*parent
, struct window
*previous
)
110 unlink_window( win
); /* unlink it from the previous location */
114 win
->parent
= parent
;
115 if ((win
->prev
= previous
))
117 if ((win
->next
= previous
->next
)) win
->next
->prev
= win
;
118 else if (win
->parent
->last_child
== previous
) win
->parent
->last_child
= win
;
119 win
->prev
->next
= win
;
123 if ((win
->next
= parent
->first_child
)) win
->next
->prev
= win
;
124 else win
->parent
->last_child
= win
;
125 parent
->first_child
= win
;
128 else /* move it to parent unlinked list */
130 parent
= win
->parent
;
131 if ((win
->next
= parent
->first_unlinked
)) win
->next
->prev
= win
;
133 parent
->first_unlinked
= win
;
137 /* set a window property */
138 static void set_property( struct window
*win
, atom_t atom
, obj_handle_t handle
,
139 enum property_type type
)
142 struct property
*new_props
;
144 /* check if it exists already */
145 for (i
= 0; i
< win
->prop_inuse
; i
++)
147 if (win
->properties
[i
].type
== PROP_TYPE_FREE
)
152 if (win
->properties
[i
].atom
== atom
)
154 win
->properties
[i
].type
= type
;
155 win
->properties
[i
].handle
= handle
;
160 /* need to add an entry */
161 if (!grab_global_atom( atom
)) return;
165 if (win
->prop_inuse
>= win
->prop_alloc
)
167 /* need to grow the array */
168 if (!(new_props
= realloc( win
->properties
,
169 sizeof(*new_props
) * (win
->prop_alloc
+ 16) )))
171 set_error( STATUS_NO_MEMORY
);
172 release_global_atom( atom
);
175 win
->prop_alloc
+= 16;
176 win
->properties
= new_props
;
178 free
= win
->prop_inuse
++;
180 win
->properties
[free
].atom
= atom
;
181 win
->properties
[free
].type
= type
;
182 win
->properties
[free
].handle
= handle
;
185 /* remove a window property */
186 static obj_handle_t
remove_property( struct window
*win
, atom_t atom
)
190 for (i
= 0; i
< win
->prop_inuse
; i
++)
192 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
193 if (win
->properties
[i
].atom
== atom
)
195 release_global_atom( atom
);
196 win
->properties
[i
].type
= PROP_TYPE_FREE
;
197 return win
->properties
[i
].handle
;
200 /* FIXME: last error? */
204 /* find a window property */
205 static obj_handle_t
get_property( struct window
*win
, atom_t atom
)
209 for (i
= 0; i
< win
->prop_inuse
; i
++)
211 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
212 if (win
->properties
[i
].atom
== atom
) return win
->properties
[i
].handle
;
214 /* FIXME: last error? */
218 /* destroy all properties of a window */
219 inline static void destroy_properties( struct window
*win
)
223 if (!win
->properties
) return;
224 for (i
= 0; i
< win
->prop_inuse
; i
++)
226 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
227 release_global_atom( win
->properties
[i
].atom
);
229 free( win
->properties
);
232 /* destroy a window */
233 static void destroy_window( struct window
*win
)
235 assert( win
!= top_window
);
237 /* destroy all children */
238 while (win
->first_child
) destroy_window( win
->first_child
);
239 while (win
->first_unlinked
) destroy_window( win
->first_unlinked
);
241 if (win
->thread
->queue
)
243 if (win
->paint_count
) inc_queue_paint_count( win
->thread
, -win
->paint_count
);
244 queue_cleanup_window( win
->thread
, win
->handle
);
246 free_user_handle( win
->handle
);
247 destroy_properties( win
);
248 unlink_window( win
);
249 if (win
->text
) free( win
->text
);
250 memset( win
, 0x55, sizeof(*win
) );
254 /* create a new window structure (note: the window is not linked in the window tree) */
255 static struct window
*create_window( struct window
*parent
, struct window
*owner
, atom_t atom
)
257 struct window
*win
= mem_alloc( sizeof(*win
) );
258 if (!win
) return NULL
;
260 if (!(win
->handle
= alloc_user_handle( win
, USER_WINDOW
)))
265 win
->parent
= parent
;
266 win
->owner
= owner
? owner
->handle
: 0;
267 win
->first_child
= NULL
;
268 win
->last_child
= NULL
;
269 win
->first_unlinked
= NULL
;
270 win
->thread
= current
;
272 win
->last_active
= win
->handle
;
276 win
->instance
= NULL
;
277 win
->user_data
= NULL
;
279 win
->paint_count
= 0;
282 win
->properties
= NULL
;
284 if (parent
) /* put it on parent unlinked list */
286 if ((win
->next
= parent
->first_unlinked
)) win
->next
->prev
= win
;
288 parent
->first_unlinked
= win
;
290 else win
->next
= win
->prev
= NULL
;
292 /* if parent belongs to a different thread, attach the two threads */
293 if (parent
&& parent
->thread
&& parent
->thread
!= current
)
294 attach_thread_input( current
, parent
->thread
);
298 /* destroy all windows belonging to a given thread */
299 void destroy_thread_windows( struct thread
*thread
)
301 user_handle_t handle
= 0;
304 while ((win
= next_user_handle( &handle
, USER_WINDOW
)))
306 if (win
->thread
!= thread
) continue;
307 destroy_window( win
);
311 /* check whether child is a descendant of parent */
312 int is_child_window( user_handle_t parent
, user_handle_t child
)
314 struct window
*child_ptr
= get_user_object( child
, USER_WINDOW
);
315 struct window
*parent_ptr
= get_user_object( parent
, USER_WINDOW
);
317 if (!child_ptr
|| !parent_ptr
) return 0;
318 while (child_ptr
->parent
)
320 if (child_ptr
->parent
== parent_ptr
) return 1;
321 child_ptr
= child_ptr
->parent
;
326 /* check whether window is a top-level window */
327 int is_top_level_window( user_handle_t window
)
329 struct window
*win
= get_user_object( window
, USER_WINDOW
);
330 return (win
&& win
->parent
== top_window
);
333 /* make a window active if possible */
334 int make_window_active( user_handle_t window
)
336 struct window
*owner
, *win
= get_window( window
);
340 /* set last active for window and its owner */
341 win
->last_active
= win
->handle
;
342 if ((owner
= get_user_object( win
->owner
, USER_WINDOW
))) owner
->last_active
= win
->handle
;
347 /* return the thread owning a window */
348 struct thread
*get_window_thread( user_handle_t handle
)
350 struct window
*win
= get_user_object( handle
, USER_WINDOW
);
351 if (!win
|| !win
->thread
) return NULL
;
352 return (struct thread
*)grab_object( win
->thread
);
355 /* find a child of the specified window that needs repainting */
356 static struct window
*find_child_to_repaint( struct window
*parent
, struct thread
*thread
)
358 struct window
*ptr
, *ret
= NULL
;
360 for (ptr
= parent
->first_child
; ptr
&& !ret
; ptr
= ptr
->next
)
362 if (!(ptr
->style
& WS_VISIBLE
)) continue;
363 if (ptr
->paint_count
&& ptr
->thread
== thread
)
365 else /* explore its children */
366 ret
= find_child_to_repaint( ptr
, thread
);
369 if (ret
&& (ret
->ex_style
& WS_EX_TRANSPARENT
))
371 /* transparent window, check for non-transparent sibling to paint first */
372 for (ptr
= ret
->next
; ptr
; ptr
= ptr
->next
)
374 if (!(ptr
->style
& WS_VISIBLE
)) continue;
375 if (ptr
->ex_style
& WS_EX_TRANSPARENT
) continue;
376 if (ptr
->paint_count
&& ptr
->thread
== thread
) return ptr
;
383 /* find a window that needs repainting */
384 user_handle_t
find_window_to_repaint( user_handle_t parent
, struct thread
*thread
)
386 struct window
*win
= parent
? get_window( parent
) : top_window
;
388 if (!win
|| !(win
->style
& WS_VISIBLE
)) return 0;
389 if (!win
->paint_count
|| win
->thread
!= thread
)
390 win
= find_child_to_repaint( win
, thread
);
391 return win
? win
->handle
: 0;
395 /* create a window */
396 DECL_HANDLER(create_window
)
399 if (!req
->parent
) /* return desktop window */
403 if (!(top_window
= create_window( NULL
, NULL
, req
->atom
))) return;
404 top_window
->thread
= NULL
; /* no thread owns the desktop */
405 top_window
->style
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
407 reply
->handle
= top_window
->handle
;
411 struct window
*win
, *parent
, *owner
= NULL
;
413 if (!(parent
= get_window( req
->parent
))) return;
414 if (req
->owner
&& !(owner
= get_window( req
->owner
))) return;
415 if (owner
== top_window
) owner
= NULL
;
416 else if (owner
&& parent
!= top_window
)
418 /* an owned window must be created as top-level */
419 set_error( STATUS_ACCESS_DENIED
);
422 if (!(win
= create_window( parent
, owner
, req
->atom
))) return;
423 reply
->handle
= win
->handle
;
428 /* link a window into the tree */
429 DECL_HANDLER(link_window
)
431 struct window
*win
, *parent
= NULL
, *previous
= NULL
;
433 if (!(win
= get_window( req
->handle
))) return;
434 if (req
->parent
&& !(parent
= get_window( req
->parent
))) return;
436 if (win
== top_window
)
438 set_error( STATUS_INVALID_PARAMETER
);
441 reply
->full_parent
= parent
? parent
->handle
: 0;
442 if (parent
&& req
->previous
)
444 if (req
->previous
== (user_handle_t
)1) /* special case: HWND_BOTTOM */
446 previous
= parent
->last_child
;
447 if (previous
== win
) return; /* nothing to do */
451 if (!(previous
= get_window( req
->previous
))) return;
452 /* previous must be a child of parent, and not win itself */
453 if (previous
->parent
!= parent
|| previous
== win
)
455 set_error( STATUS_INVALID_PARAMETER
);
460 link_window( win
, parent
, previous
);
464 /* destroy a window */
465 DECL_HANDLER(destroy_window
)
467 struct window
*win
= get_window( req
->handle
);
470 if (win
!= top_window
) destroy_window( win
);
471 else set_error( STATUS_ACCESS_DENIED
);
476 /* set a window owner */
477 DECL_HANDLER(set_window_owner
)
479 struct window
*win
= get_window( req
->handle
);
480 struct window
*owner
= NULL
;
483 if (req
->owner
&& !(owner
= get_window( req
->owner
))) return;
484 if (win
== top_window
)
486 set_error( STATUS_ACCESS_DENIED
);
489 reply
->prev_owner
= win
->owner
;
490 reply
->full_owner
= win
->owner
= owner
? owner
->handle
: 0;
494 /* get information from a window handle */
495 DECL_HANDLER(get_window_info
)
497 struct window
*win
= get_window( req
->handle
);
499 reply
->full_handle
= 0;
500 reply
->tid
= reply
->pid
= 0;
503 reply
->full_handle
= win
->handle
;
504 reply
->last_active
= win
->handle
;
505 if (get_user_object( win
->last_active
, USER_WINDOW
)) reply
->last_active
= win
->last_active
;
508 reply
->tid
= get_thread_id( win
->thread
);
509 reply
->pid
= get_process_id( win
->thread
->process
);
510 reply
->atom
= win
->atom
;
516 /* set some information in a window */
517 DECL_HANDLER(set_window_info
)
519 struct window
*win
= get_window( req
->handle
);
522 if (req
->flags
&& win
== top_window
)
524 set_error( STATUS_ACCESS_DENIED
);
527 reply
->old_style
= win
->style
;
528 reply
->old_ex_style
= win
->ex_style
;
529 reply
->old_id
= win
->id
;
530 reply
->old_instance
= win
->instance
;
531 reply
->old_user_data
= win
->user_data
;
532 if (req
->flags
& SET_WIN_STYLE
) win
->style
= req
->style
;
533 if (req
->flags
& SET_WIN_EXSTYLE
) win
->ex_style
= req
->ex_style
;
534 if (req
->flags
& SET_WIN_ID
) win
->id
= req
->id
;
535 if (req
->flags
& SET_WIN_INSTANCE
) win
->instance
= req
->instance
;
536 if (req
->flags
& SET_WIN_USERDATA
) win
->user_data
= req
->user_data
;
540 /* get a list of the window parents, up to the root of the tree */
541 DECL_HANDLER(get_window_parents
)
543 struct window
*ptr
, *win
= get_window( req
->handle
);
548 if (win
) for (ptr
= win
->parent
; ptr
; ptr
= ptr
->parent
) total
++;
550 reply
->count
= total
;
551 len
= min( get_reply_max_size(), total
* sizeof(user_handle_t
) );
552 if (len
&& ((data
= set_reply_data_size( len
))))
554 for (ptr
= win
->parent
; ptr
&& len
; ptr
= ptr
->parent
, len
-= sizeof(*data
))
555 *data
++ = ptr
->handle
;
560 /* get a list of the window children */
561 DECL_HANDLER(get_window_children
)
563 struct window
*ptr
, *parent
= get_window( req
->parent
);
569 for (ptr
= parent
->first_child
, total
= 0; ptr
; ptr
= ptr
->next
)
571 if (req
->atom
&& ptr
->atom
!= req
->atom
) continue;
572 if (req
->tid
&& get_thread_id(ptr
->thread
) != req
->tid
) continue;
576 reply
->count
= total
;
577 len
= min( get_reply_max_size(), total
* sizeof(user_handle_t
) );
578 if (len
&& ((data
= set_reply_data_size( len
))))
580 for (ptr
= parent
->first_child
; ptr
&& len
; ptr
= ptr
->next
)
582 if (req
->atom
&& ptr
->atom
!= req
->atom
) continue;
583 if (req
->tid
&& get_thread_id(ptr
->thread
) != req
->tid
) continue;
584 *data
++ = ptr
->handle
;
585 len
-= sizeof(*data
);
591 /* get window tree information from a window handle */
592 DECL_HANDLER(get_window_tree
)
594 struct window
*win
= get_window( req
->handle
);
600 struct window
*parent
= win
->parent
;
601 reply
->parent
= parent
->handle
;
602 reply
->owner
= win
->owner
;
603 reply
->next_sibling
= win
->next
? win
->next
->handle
: 0;
604 reply
->prev_sibling
= win
->prev
? win
->prev
->handle
: 0;
605 reply
->first_sibling
= parent
->first_child
? parent
->first_child
->handle
: 0;
606 reply
->last_sibling
= parent
->last_child
? parent
->last_child
->handle
: 0;
612 reply
->next_sibling
= 0;
613 reply
->prev_sibling
= 0;
614 reply
->first_sibling
= 0;
615 reply
->last_sibling
= 0;
617 reply
->first_child
= win
->first_child
? win
->first_child
->handle
: 0;
618 reply
->last_child
= win
->last_child
? win
->last_child
->handle
: 0;
622 /* set the window and client rectangles of a window */
623 DECL_HANDLER(set_window_rectangles
)
625 struct window
*win
= get_window( req
->handle
);
629 win
->window_rect
= req
->window
;
630 win
->client_rect
= req
->client
;
635 /* get the window and client rectangles of a window */
636 DECL_HANDLER(get_window_rectangles
)
638 struct window
*win
= get_window( req
->handle
);
642 reply
->window
= win
->window_rect
;
643 reply
->client
= win
->client_rect
;
648 /* get the window text */
649 DECL_HANDLER(get_window_text
)
651 struct window
*win
= get_window( req
->handle
);
653 if (win
&& win
->text
)
655 size_t len
= strlenW( win
->text
) * sizeof(WCHAR
);
656 if (len
> get_reply_max_size()) len
= get_reply_max_size();
657 set_reply_data( win
->text
, len
);
662 /* set the window text */
663 DECL_HANDLER(set_window_text
)
665 struct window
*win
= get_window( req
->handle
);
670 size_t len
= get_req_data_size() / sizeof(WCHAR
);
673 if (!(text
= mem_alloc( (len
+1) * sizeof(WCHAR
) ))) return;
674 memcpy( text
, get_req_data(), len
* sizeof(WCHAR
) );
677 if (win
->text
) free( win
->text
);
683 /* increment the window paint count */
684 DECL_HANDLER(inc_window_paint_count
)
686 struct window
*win
= get_window( req
->handle
);
688 if (win
&& win
->thread
)
690 int old
= win
->paint_count
;
691 if ((win
->paint_count
+= req
->incr
) < 0) win
->paint_count
= 0;
692 inc_queue_paint_count( win
->thread
, win
->paint_count
- old
);
697 /* get the coordinates offset between two windows */
698 DECL_HANDLER(get_windows_offset
)
702 reply
->x
= reply
->y
= 0;
705 if (!(win
= get_window( req
->from
))) return;
708 reply
->x
+= win
->client_rect
.left
;
709 reply
->y
+= win
->client_rect
.top
;
715 if (!(win
= get_window( req
->to
))) return;
718 reply
->x
-= win
->client_rect
.left
;
719 reply
->y
-= win
->client_rect
.top
;
726 /* set a window property */
727 DECL_HANDLER(set_window_property
)
729 struct window
*win
= get_window( req
->window
);
731 if (win
) set_property( win
, req
->atom
, req
->handle
,
732 req
->string
? PROP_TYPE_STRING
: PROP_TYPE_ATOM
);
736 /* remove a window property */
737 DECL_HANDLER(remove_window_property
)
739 struct window
*win
= get_window( req
->window
);
741 if (win
) reply
->handle
= remove_property( win
, req
->atom
);
745 /* get a window property */
746 DECL_HANDLER(get_window_property
)
748 struct window
*win
= get_window( req
->window
);
750 if (win
) reply
->handle
= get_property( win
, req
->atom
);
754 /* get the list of properties of a window */
755 DECL_HANDLER(get_window_properties
)
757 property_data_t
*data
;
758 int i
, count
, max
= get_reply_max_size() / sizeof(*data
);
759 struct window
*win
= get_window( req
->window
);
764 for (i
= count
= 0; i
< win
->prop_inuse
; i
++)
765 if (win
->properties
[i
].type
!= PROP_TYPE_FREE
) count
++;
766 reply
->total
= count
;
768 if (count
> max
) count
= max
;
769 if (!count
|| !(data
= set_reply_data_size( count
* sizeof(*data
) ))) return;
771 for (i
= 0; i
< win
->prop_inuse
&& count
; i
++)
773 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
774 data
->atom
= win
->properties
[i
].atom
;
775 data
->string
= (win
->properties
[i
].type
== PROP_TYPE_STRING
);
776 data
->handle
= win
->properties
[i
].handle
;