2 * Server-side window handling
4 * Copyright (C) 2001 Alexandre Julliard
20 /* a window property */
23 unsigned short type
; /* property type (see below) */
24 atom_t atom
; /* property atom */
25 handle_t handle
; /* property handle (user-defined storage) */
30 PROP_TYPE_FREE
, /* free entry */
31 PROP_TYPE_STRING
, /* atom that was originally a string */
32 PROP_TYPE_ATOM
/* plain atom */
38 struct window
*parent
; /* parent window */
39 struct window
*owner
; /* owner of this window */
40 struct window
*first_child
; /* first child in Z-order */
41 struct window
*last_child
; /* last child in Z-order */
42 struct window
*first_unlinked
; /* first child not linked in the Z-order list */
43 struct window
*next
; /* next window in Z-order */
44 struct window
*prev
; /* prev window in Z-order */
45 user_handle_t handle
; /* full handle for this window */
46 struct thread
*thread
; /* thread owning the window */
47 atom_t atom
; /* class atom */
48 rectangle_t window_rect
; /* window rectangle */
49 rectangle_t client_rect
; /* client rectangle */
50 unsigned int style
; /* window style */
51 unsigned int ex_style
; /* window extended style */
52 unsigned int id
; /* window id */
53 void* instance
; /* creator instance */
54 void* user_data
; /* user-specific data */
55 WCHAR
*text
; /* window caption text */
56 int paint_count
; /* count of pending paints for this window */
57 int prop_inuse
; /* number of in-use window properties */
58 int prop_alloc
; /* number of allocated window properties */
59 struct property
*properties
; /* window properties array */
62 static struct window
*top_window
; /* top-level (desktop) window */
65 /* retrieve a pointer to a window from its handle */
66 inline static struct window
*get_window( user_handle_t handle
)
68 struct window
*ret
= get_user_object( handle
, USER_WINDOW
);
69 if (!ret
) set_error( STATUS_INVALID_HANDLE
);
73 /* unlink a window from the tree */
74 static void unlink_window( struct window
*win
)
76 struct window
*parent
= win
->parent
;
80 if (win
->next
) win
->next
->prev
= win
->prev
;
81 else if (parent
->last_child
== win
) parent
->last_child
= win
->prev
;
83 if (win
->prev
) win
->prev
->next
= win
->next
;
84 else if (parent
->first_child
== win
) parent
->first_child
= win
->next
;
85 else if (parent
->first_unlinked
== win
) parent
->first_unlinked
= win
->next
;
89 /* link a window into the tree (or unlink it if the new parent is NULL) */
90 static void link_window( struct window
*win
, struct window
*parent
, struct window
*previous
)
92 unlink_window( win
); /* unlink it from the previous location */
96 if (win
->parent
!= parent
)
98 win
->owner
= NULL
; /* reset owner if changing parent */
101 if ((win
->prev
= previous
))
103 if ((win
->next
= previous
->next
)) win
->next
->prev
= win
;
104 else if (win
->parent
->last_child
== previous
) win
->parent
->last_child
= win
;
105 win
->prev
->next
= win
;
109 if ((win
->next
= parent
->first_child
)) win
->next
->prev
= win
;
110 else win
->parent
->last_child
= win
;
111 parent
->first_child
= win
;
114 else /* move it to parent unlinked list */
116 parent
= win
->parent
;
117 if ((win
->next
= parent
->first_unlinked
)) win
->next
->prev
= win
;
119 parent
->first_unlinked
= win
;
123 /* set a window property */
124 static void set_property( struct window
*win
, atom_t atom
, handle_t handle
,
125 enum property_type type
)
128 struct property
*new_props
;
130 /* check if it exists already */
131 for (i
= 0; i
< win
->prop_inuse
; i
++)
133 if (win
->properties
[i
].type
== PROP_TYPE_FREE
)
138 if (win
->properties
[i
].atom
== atom
)
140 win
->properties
[i
].type
= type
;
141 win
->properties
[i
].handle
= handle
;
146 /* need to add an entry */
147 if (!grab_global_atom( atom
)) return;
151 if (win
->prop_inuse
>= win
->prop_alloc
)
153 /* need to grow the array */
154 if (!(new_props
= realloc( win
->properties
,
155 sizeof(*new_props
) * (win
->prop_alloc
+ 16) )))
157 set_error( STATUS_NO_MEMORY
);
158 release_global_atom( atom
);
161 win
->prop_alloc
+= 16;
162 win
->properties
= new_props
;
164 free
= win
->prop_inuse
++;
166 win
->properties
[free
].atom
= atom
;
167 win
->properties
[free
].type
= type
;
168 win
->properties
[free
].handle
= handle
;
171 /* remove a window property */
172 static handle_t
remove_property( struct window
*win
, atom_t atom
)
176 for (i
= 0; i
< win
->prop_inuse
; i
++)
178 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
179 if (win
->properties
[i
].atom
== atom
)
181 release_global_atom( atom
);
182 win
->properties
[i
].type
= PROP_TYPE_FREE
;
183 return win
->properties
[i
].handle
;
186 /* FIXME: last error? */
190 /* find a window property */
191 static handle_t
get_property( struct window
*win
, atom_t atom
)
195 for (i
= 0; i
< win
->prop_inuse
; i
++)
197 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
198 if (win
->properties
[i
].atom
== atom
) return win
->properties
[i
].handle
;
200 /* FIXME: last error? */
204 /* destroy all properties of a window */
205 inline static void destroy_properties( struct window
*win
)
209 if (!win
->properties
) return;
210 for (i
= 0; i
< win
->prop_inuse
; i
++)
212 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
213 release_global_atom( win
->properties
[i
].atom
);
215 free( win
->properties
);
218 /* enum all properties into the data array */
219 static int enum_properties( struct window
*win
, property_data_t
*data
, int max
)
223 for (i
= count
= 0; i
< win
->prop_inuse
&& count
< max
; i
++)
225 if (win
->properties
[i
].type
== PROP_TYPE_FREE
) continue;
226 data
->atom
= win
->properties
[i
].atom
;
227 data
->string
= (win
->properties
[i
].type
== PROP_TYPE_STRING
);
228 data
->handle
= win
->properties
[i
].handle
;
235 /* destroy a window */
236 static void destroy_window( struct window
*win
)
238 assert( win
!= top_window
);
240 /* destroy all children */
241 while (win
->first_child
) destroy_window( win
->first_child
);
242 while (win
->first_unlinked
) destroy_window( win
->first_unlinked
);
244 /* reset siblings owner */
248 for (ptr
= win
->parent
->first_child
; ptr
; ptr
= ptr
->next
)
249 if (ptr
->owner
== win
) ptr
->owner
= NULL
;
250 for (ptr
= win
->parent
->first_unlinked
; ptr
; ptr
= ptr
->next
)
251 if (ptr
->owner
== win
) ptr
->owner
= NULL
;
254 if (win
->paint_count
) inc_queue_paint_count( win
->thread
, -win
->paint_count
);
255 queue_cleanup_window( win
->thread
, win
->handle
);
256 free_user_handle( win
->handle
);
257 destroy_properties( win
);
258 unlink_window( win
);
259 if (win
->text
) free( win
->text
);
260 memset( win
, 0x55, sizeof(*win
) );
264 /* create a new window structure (note: the window is not linked in the window tree) */
265 static struct window
*create_window( struct window
*parent
, struct window
*owner
, atom_t atom
)
267 struct window
*win
= mem_alloc( sizeof(*win
) );
268 if (!win
) return NULL
;
270 if (!(win
->handle
= alloc_user_handle( win
, USER_WINDOW
)))
275 win
->parent
= parent
;
277 win
->first_child
= NULL
;
278 win
->last_child
= NULL
;
279 win
->first_unlinked
= NULL
;
280 win
->thread
= current
;
285 win
->instance
= NULL
;
286 win
->user_data
= NULL
;
288 win
->paint_count
= 0;
291 win
->properties
= NULL
;
293 if (parent
) /* put it on parent unlinked list */
295 if ((win
->next
= parent
->first_unlinked
)) win
->next
->prev
= win
;
297 parent
->first_unlinked
= win
;
299 else win
->next
= win
->prev
= NULL
;
304 /* destroy all windows belonging to a given thread */
305 void destroy_thread_windows( struct thread
*thread
)
307 user_handle_t handle
= 0;
310 while ((win
= next_user_handle( &handle
, USER_WINDOW
)))
312 if (win
->thread
!= thread
) continue;
313 destroy_window( win
);
317 /* check whether child is a descendant of parent */
318 int is_child_window( user_handle_t parent
, user_handle_t child
)
320 struct window
*child_ptr
= get_user_object( child
, USER_WINDOW
);
321 struct window
*parent_ptr
= get_user_object( parent
, USER_WINDOW
);
323 if (!child_ptr
|| !parent_ptr
) return 0;
324 while (child_ptr
->parent
)
326 if (child_ptr
->parent
== parent_ptr
) return 1;
327 child_ptr
= child_ptr
->parent
;
333 /* find a child of the specified window that needs repainting */
334 static struct window
*find_child_to_repaint( struct window
*parent
, struct thread
*thread
)
336 struct window
*ptr
, *ret
= NULL
;
338 for (ptr
= parent
->first_child
; ptr
&& !ret
; ptr
= ptr
->next
)
340 if (!(ptr
->style
& WS_VISIBLE
)) continue;
341 if (ptr
->paint_count
&& ptr
->thread
== thread
)
343 else /* explore its children */
344 ret
= find_child_to_repaint( ptr
, thread
);
347 if (ret
&& (ret
->ex_style
& WS_EX_TRANSPARENT
))
349 /* transparent window, check for non-transparent sibling to paint first */
350 for (ptr
= ret
->next
; ptr
; ptr
= ptr
->next
)
352 if (!(ptr
->style
& WS_VISIBLE
)) continue;
353 if (ptr
->ex_style
& WS_EX_TRANSPARENT
) continue;
354 if (ptr
->paint_count
&& ptr
->thread
== thread
) return ptr
;
361 /* find a window that needs repainting */
362 user_handle_t
find_window_to_repaint( user_handle_t parent
, struct thread
*thread
)
364 struct window
*win
= parent
? get_window( parent
) : top_window
;
366 if (!win
|| !(win
->style
& WS_VISIBLE
)) return 0;
367 if (!win
->paint_count
|| win
->thread
!= thread
)
368 win
= find_child_to_repaint( win
, thread
);
369 return win
? win
->handle
: 0;
373 /* create a window */
374 DECL_HANDLER(create_window
)
377 if (!req
->parent
) /* return desktop window */
381 if (!(top_window
= create_window( NULL
, NULL
, req
->atom
))) return;
382 top_window
->thread
= NULL
; /* no thread owns the desktop */
384 req
->handle
= top_window
->handle
;
388 struct window
*win
, *parent
, *owner
= NULL
;
390 if (!(parent
= get_window( req
->parent
))) return;
391 if (req
->owner
&& !(owner
= get_window( req
->owner
))) return;
392 if (owner
== top_window
) owner
= NULL
;
393 else if (owner
&& owner
->parent
!= parent
)
395 /* owner must be a sibling of the new window */
396 set_error( STATUS_ACCESS_DENIED
);
399 if (!(win
= create_window( parent
, owner
, req
->atom
))) return;
400 req
->handle
= win
->handle
;
405 /* link a window into the tree */
406 DECL_HANDLER(link_window
)
408 struct window
*win
, *parent
= NULL
, *previous
= NULL
;
410 if (!(win
= get_window( req
->handle
))) return;
411 if (req
->parent
&& !(parent
= get_window( req
->parent
))) return;
413 if (win
== top_window
)
415 set_error( STATUS_INVALID_PARAMETER
);
418 req
->full_parent
= parent
? parent
->handle
: 0;
419 if (parent
&& req
->previous
)
421 if (req
->previous
== (user_handle_t
)1) /* special case: HWND_BOTTOM */
423 previous
= parent
->last_child
;
424 if (previous
== win
) return; /* nothing to do */
428 if (!(previous
= get_window( req
->previous
))) return;
429 /* previous must be a child of parent, and not win itself */
430 if (previous
->parent
!= parent
|| previous
== win
)
432 set_error( STATUS_INVALID_PARAMETER
);
437 link_window( win
, parent
, previous
);
441 /* destroy a window */
442 DECL_HANDLER(destroy_window
)
444 struct window
*win
= get_window( req
->handle
);
447 if (win
!= top_window
) destroy_window( win
);
448 else set_error( STATUS_ACCESS_DENIED
);
453 /* set a window owner */
454 DECL_HANDLER(set_window_owner
)
456 struct window
*win
= get_window( req
->handle
);
457 struct window
*owner
= get_window( req
->owner
);
459 if (!win
|| !owner
) return;
460 if (owner
->parent
!= win
->parent
)
462 /* owner has to be a sibling of window */
463 set_error( STATUS_ACCESS_DENIED
);
467 req
->full_owner
= owner
->handle
;
471 /* get information from a window handle */
472 DECL_HANDLER(get_window_info
)
474 struct window
*win
= get_window( req
->handle
);
476 req
->full_handle
= 0;
477 req
->tid
= req
->pid
= 0;
480 req
->full_handle
= win
->handle
;
483 req
->tid
= get_thread_id( win
->thread
);
484 req
->pid
= get_process_id( win
->thread
->process
);
485 req
->atom
= win
->atom
;
491 /* set some information in a window */
492 DECL_HANDLER(set_window_info
)
494 struct window
*win
= get_window( req
->handle
);
496 req
->old_style
= win
->style
;
497 req
->old_ex_style
= win
->ex_style
;
498 req
->old_id
= win
->id
;
499 req
->old_instance
= win
->instance
;
500 req
->old_user_data
= win
->user_data
;
501 if (req
->flags
& SET_WIN_STYLE
) win
->style
= req
->style
;
502 if (req
->flags
& SET_WIN_EXSTYLE
) win
->ex_style
= req
->ex_style
;
503 if (req
->flags
& SET_WIN_ID
) win
->id
= req
->id
;
504 if (req
->flags
& SET_WIN_INSTANCE
) win
->instance
= req
->instance
;
505 if (req
->flags
& SET_WIN_USERDATA
) win
->user_data
= req
->user_data
;
509 /* get a list of the window parents, up to the root of the tree */
510 DECL_HANDLER(get_window_parents
)
512 struct window
*ptr
, *win
= get_window( req
->handle
);
516 if (win
) for (ptr
= win
->parent
; ptr
; ptr
= ptr
->parent
) total
++;
519 len
= min( get_req_data_size(req
), total
* sizeof(user_handle_t
) );
520 set_req_data_size( req
, len
);
523 user_handle_t
*data
= get_req_data(req
);
524 for (ptr
= win
->parent
; ptr
&& len
; ptr
= ptr
->parent
, len
-= sizeof(*data
))
525 *data
++ = ptr
->handle
;
530 /* get a list of the window children */
531 DECL_HANDLER(get_window_children
)
533 struct window
*ptr
, *parent
= get_window( req
->parent
);
538 for (ptr
= parent
->first_child
, total
= 0; ptr
; ptr
= ptr
->next
)
540 if (req
->atom
&& ptr
->atom
!= req
->atom
) continue;
541 if (req
->tid
&& get_thread_id(ptr
->thread
) != req
->tid
) continue;
546 len
= min( get_req_data_size(req
), total
* sizeof(user_handle_t
) );
547 set_req_data_size( req
, len
);
550 user_handle_t
*data
= get_req_data(req
);
551 for (ptr
= parent
->first_child
; ptr
&& len
; ptr
= ptr
->next
, len
-= sizeof(*data
))
553 if (req
->atom
&& ptr
->atom
!= req
->atom
) continue;
554 if (req
->tid
&& get_thread_id(ptr
->thread
) != req
->tid
) continue;
555 *data
++ = ptr
->handle
;
561 /* get window tree information from a window handle */
562 DECL_HANDLER(get_window_tree
)
564 struct window
*win
= get_window( req
->handle
);
570 struct window
*parent
= win
->parent
;
571 req
->parent
= parent
->handle
;
572 req
->owner
= win
->owner
? win
->owner
->handle
: 0;
573 req
->next_sibling
= win
->next
? win
->next
->handle
: 0;
574 req
->prev_sibling
= win
->prev
? win
->prev
->handle
: 0;
575 req
->first_sibling
= parent
->first_child
? parent
->first_child
->handle
: 0;
576 req
->last_sibling
= parent
->last_child
? parent
->last_child
->handle
: 0;
582 req
->next_sibling
= 0;
583 req
->prev_sibling
= 0;
584 req
->first_sibling
= 0;
585 req
->last_sibling
= 0;
587 req
->first_child
= win
->first_child
? win
->first_child
->handle
: 0;
588 req
->last_child
= win
->last_child
? win
->last_child
->handle
: 0;
592 /* set the window and client rectangles of a window */
593 DECL_HANDLER(set_window_rectangles
)
595 struct window
*win
= get_window( req
->handle
);
599 win
->window_rect
= req
->window
;
600 win
->client_rect
= req
->client
;
605 /* get the window and client rectangles of a window */
606 DECL_HANDLER(get_window_rectangles
)
608 struct window
*win
= get_window( req
->handle
);
612 req
->window
= win
->window_rect
;
613 req
->client
= win
->client_rect
;
618 /* get the window text */
619 DECL_HANDLER(get_window_text
)
621 struct window
*win
= get_window( req
->handle
);
624 if (win
&& win
->text
)
626 len
= strlenW( win
->text
) * sizeof(WCHAR
);
627 if (len
> get_req_data_size(req
)) len
= get_req_data_size(req
);
628 memcpy( get_req_data(req
), win
->text
, len
);
630 set_req_data_size( req
, len
);
634 /* set the window text */
635 DECL_HANDLER(set_window_text
)
637 struct window
*win
= get_window( req
->handle
);
642 size_t len
= get_req_data_size(req
) / sizeof(WCHAR
);
645 if (!(text
= mem_alloc( (len
+1) * sizeof(WCHAR
) ))) return;
646 memcpy( text
, get_req_data(req
), len
* sizeof(WCHAR
) );
649 if (win
->text
) free( win
->text
);
655 /* increment the window paint count */
656 DECL_HANDLER(inc_window_paint_count
)
658 struct window
*win
= get_window( req
->handle
);
660 if (win
&& win
->thread
)
662 int old
= win
->paint_count
;
663 if ((win
->paint_count
+= req
->incr
) < 0) win
->paint_count
= 0;
664 inc_queue_paint_count( win
->thread
, win
->paint_count
- old
);
669 /* get the coordinates offset between two windows */
670 DECL_HANDLER(get_windows_offset
)
677 if (!(win
= get_window( req
->from
))) return;
680 req
->x
+= win
->client_rect
.left
;
681 req
->y
+= win
->client_rect
.top
;
687 if (!(win
= get_window( req
->to
))) return;
690 req
->x
-= win
->client_rect
.left
;
691 req
->y
-= win
->client_rect
.top
;
698 /* set a window property */
699 DECL_HANDLER(set_window_property
)
701 struct window
*win
= get_window( req
->window
);
703 if (win
) set_property( win
, req
->atom
, req
->handle
,
704 req
->string
? PROP_TYPE_STRING
: PROP_TYPE_ATOM
);
708 /* remove a window property */
709 DECL_HANDLER(remove_window_property
)
711 struct window
*win
= get_window( req
->window
);
713 if (win
) req
->handle
= remove_property( win
, req
->atom
);
717 /* get a window property */
718 DECL_HANDLER(get_window_property
)
720 struct window
*win
= get_window( req
->window
);
722 if (win
) req
->handle
= get_property( win
, req
->atom
);
726 /* get the list of properties of a window */
727 DECL_HANDLER(get_window_properties
)
730 property_data_t
*data
= get_req_data(req
);
731 struct window
*win
= get_window( req
->window
);
733 if (win
) count
= enum_properties( win
, data
, get_req_data_size(req
) / sizeof(*data
) );
734 set_req_data_size( req
, count
* sizeof(*data
) );