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"
39 /* a window property */
42 unsigned short type; /* property type (see below) */
43 atom_t atom; /* property atom */
44 obj_handle_t handle; /* property handle (user-defined storage) */
49 PROP_TYPE_FREE, /* free entry */
50 PROP_TYPE_STRING, /* atom that was originally a string */
51 PROP_TYPE_ATOM /* plain atom */
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 unsigned int style; /* window style */
72 unsigned int ex_style; /* window extended style */
73 unsigned int id; /* window id */
74 void* instance; /* creator instance */
75 void* user_data; /* user-specific data */
76 WCHAR *text; /* window caption text */
77 int paint_count; /* count of pending paints for this window */
78 int prop_inuse; /* number of in-use window properties */
79 int prop_alloc; /* number of allocated window properties */
80 struct property *properties; /* window properties array */
81 int nb_extra_bytes; /* number of extra bytes */
82 char extra_bytes[1]; /* extra bytes storage */
85 static struct window *top_window; /* top-level (desktop) window */
87 /* global window pointers */
88 static struct window *shell_window;
89 static struct window *shell_listview;
90 static struct window *progman_window;
91 static struct window *taskman_window;
93 /* retrieve a pointer to a window from its handle */
94 inline static struct window *get_window( user_handle_t handle )
96 struct window *ret = get_user_object( handle, USER_WINDOW );
97 if (!ret) set_error( STATUS_INVALID_HANDLE );
101 /* unlink a window from the tree */
102 static void unlink_window( struct window *win )
104 struct window *parent = win->parent;
108 if (win->next) win->next->prev = win->prev;
109 else if (parent->last_child == win) parent->last_child = win->prev;
111 if (win->prev) win->prev->next = win->next;
112 else if (parent->first_child == win) parent->first_child = win->next;
113 else if (parent->first_unlinked == win) parent->first_unlinked = win->next;
117 /* link a window into the tree (or unlink it if the new parent is NULL) */
118 static void link_window( struct window *win, struct window *parent, struct window *previous )
120 unlink_window( win ); /* unlink it from the previous location */
124 win->parent = parent;
125 if ((win->prev = previous))
127 if ((win->next = previous->next)) win->next->prev = win;
128 else if (win->parent->last_child == previous) win->parent->last_child = win;
129 win->prev->next = win;
133 if ((win->next = parent->first_child)) win->next->prev = win;
134 else win->parent->last_child = win;
135 parent->first_child = win;
138 else /* move it to parent unlinked list */
140 parent = win->parent;
141 if ((win->next = parent->first_unlinked)) win->next->prev = win;
143 parent->first_unlinked = win;
147 /* set a window property */
148 static void set_property( struct window *win, atom_t atom, obj_handle_t handle,
149 enum property_type type )
152 struct property *new_props;
154 /* check if it exists already */
155 for (i = 0; i < win->prop_inuse; i++)
157 if (win->properties[i].type == PROP_TYPE_FREE)
162 if (win->properties[i].atom == atom)
164 win->properties[i].type = type;
165 win->properties[i].handle = handle;
170 /* need to add an entry */
171 if (!grab_global_atom( atom )) return;
175 if (win->prop_inuse >= win->prop_alloc)
177 /* need to grow the array */
178 if (!(new_props = realloc( win->properties,
179 sizeof(*new_props) * (win->prop_alloc + 16) )))
181 set_error( STATUS_NO_MEMORY );
182 release_global_atom( atom );
185 win->prop_alloc += 16;
186 win->properties = new_props;
188 free = win->prop_inuse++;
190 win->properties[free].atom = atom;
191 win->properties[free].type = type;
192 win->properties[free].handle = handle;
195 /* remove a window property */
196 static obj_handle_t remove_property( struct window *win, atom_t atom )
200 for (i = 0; i < win->prop_inuse; i++)
202 if (win->properties[i].type == PROP_TYPE_FREE) continue;
203 if (win->properties[i].atom == atom)
205 release_global_atom( atom );
206 win->properties[i].type = PROP_TYPE_FREE;
207 return win->properties[i].handle;
210 /* FIXME: last error? */
214 /* find a window property */
215 static obj_handle_t get_property( struct window *win, atom_t atom )
219 for (i = 0; i < win->prop_inuse; i++)
221 if (win->properties[i].type == PROP_TYPE_FREE) continue;
222 if (win->properties[i].atom == atom) return win->properties[i].handle;
224 /* FIXME: last error? */
228 /* destroy all properties of a window */
229 inline static void destroy_properties( struct window *win )
233 if (!win->properties) return;
234 for (i = 0; i < win->prop_inuse; i++)
236 if (win->properties[i].type == PROP_TYPE_FREE) continue;
237 release_global_atom( win->properties[i].atom );
239 free( win->properties );
242 /* destroy a window */
243 static void destroy_window( struct window *win )
245 assert( win != top_window );
247 /* destroy all children */
248 while (win->first_child) destroy_window( win->first_child );
249 while (win->first_unlinked) destroy_window( win->first_unlinked );
251 if (win->thread->queue)
253 if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count );
254 queue_cleanup_window( win->thread, win->handle );
256 /* reset global window pointers, if the corresponding window is destroyed */
257 if (win == shell_window) shell_window = NULL;
258 if (win == shell_listview) shell_listview = NULL;
259 if (win == progman_window) progman_window = NULL;
260 if (win == taskman_window) taskman_window = NULL;
261 free_user_handle( win->handle );
262 destroy_properties( win );
263 unlink_window( win );
264 release_class( win->class );
265 if (win->text) free( win->text );
266 memset( win, 0x55, sizeof(*win) );
270 /* create a new window structure (note: the window is not linked in the window tree) */
271 static struct window *create_window( struct window *parent, struct window *owner, atom_t atom,
272 void *instance, int extra_bytes )
275 struct window_class *class = grab_class( current->process, atom, instance );
277 if (!class) return NULL;
279 win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
282 release_class( class );
286 if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
288 release_class( class );
292 win->parent = parent;
293 win->owner = owner ? owner->handle : 0;
294 win->first_child = NULL;
295 win->last_child = NULL;
296 win->first_unlinked = NULL;
297 win->thread = current;
300 win->last_active = win->handle;
304 win->instance = NULL;
305 win->user_data = NULL;
307 win->paint_count = 0;
310 win->properties = NULL;
311 win->nb_extra_bytes = extra_bytes;
312 memset( win->extra_bytes, 0, extra_bytes );
314 if (parent) /* put it on parent unlinked list */
316 if ((win->next = parent->first_unlinked)) win->next->prev = win;
318 parent->first_unlinked = win;
320 else win->next = win->prev = NULL;
322 /* if parent belongs to a different thread, attach the two threads */
323 if (parent && parent->thread && parent->thread != current)
324 attach_thread_input( current, parent->thread );
328 /* destroy all windows belonging to a given thread */
329 void destroy_thread_windows( struct thread *thread )
331 user_handle_t handle = 0;
334 while ((win = next_user_handle( &handle, USER_WINDOW )))
336 if (win->thread != thread) continue;
337 destroy_window( win );
341 /* check whether child is a descendant of parent */
342 int is_child_window( user_handle_t parent, user_handle_t child )
344 struct window *child_ptr = get_user_object( child, USER_WINDOW );
345 struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
347 if (!child_ptr || !parent_ptr) return 0;
348 while (child_ptr->parent)
350 if (child_ptr->parent == parent_ptr) return 1;
351 child_ptr = child_ptr->parent;
356 /* check whether window is a top-level window */
357 int is_top_level_window( user_handle_t window )
359 struct window *win = get_user_object( window, USER_WINDOW );
360 return (win && win->parent == top_window);
363 /* make a window active if possible */
364 int make_window_active( user_handle_t window )
366 struct window *owner, *win = get_window( window );
370 /* set last active for window and its owner */
371 win->last_active = win->handle;
372 if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
376 /* find child of 'parent' that contains the given point (in parent-relative coords) */
377 static struct window *child_window_from_point( struct window *parent, int x, int y )
381 for (ptr = parent->first_child; ptr; ptr = ptr->next)
383 if (!(ptr->style & WS_VISIBLE)) continue; /* not visible -> skip */
384 if ((ptr->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
385 continue; /* disabled child -> skip */
386 if ((ptr->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
387 continue; /* transparent -> skip */
388 if (x < ptr->window_rect.left || x >= ptr->window_rect.right ||
389 y < ptr->window_rect.top || y >= ptr->window_rect.bottom)
390 continue; /* not in window -> skip */
392 /* FIXME: check window region here */
394 /* if window is minimized or disabled, return at once */
395 if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
397 /* if point is not in client area, return at once */
398 if (x < ptr->client_rect.left || x >= ptr->client_rect.right ||
399 y < ptr->client_rect.top || y >= ptr->client_rect.bottom)
402 return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top );
404 return parent; /* not found any child */
407 /* find window containing point (in absolute coords) */
408 user_handle_t window_from_point( int x, int y )
412 if (!top_window) return 0;
413 ret = child_window_from_point( top_window, x, y );
417 /* return the thread owning a window */
418 struct thread *get_window_thread( user_handle_t handle )
420 struct window *win = get_user_object( handle, USER_WINDOW );
421 if (!win || !win->thread) return NULL;
422 return (struct thread *)grab_object( win->thread );
425 /* find a child of the specified window that needs repainting */
426 static struct window *find_child_to_repaint( struct window *parent, struct thread *thread )
428 struct window *ptr, *ret = NULL;
430 for (ptr = parent->first_child; ptr && !ret; ptr = ptr->next)
432 if (!(ptr->style & WS_VISIBLE)) continue;
433 if (ptr->paint_count && ptr->thread == thread)
435 else /* explore its children */
436 ret = find_child_to_repaint( ptr, thread );
439 if (ret && (ret->ex_style & WS_EX_TRANSPARENT))
441 /* transparent window, check for non-transparent sibling to paint first */
442 for (ptr = ret->next; ptr; ptr = ptr->next)
444 if (!(ptr->style & WS_VISIBLE)) continue;
445 if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
446 if (ptr->paint_count && ptr->thread == thread) return ptr;
453 /* find a window that needs repainting */
454 user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread )
456 struct window *win = parent ? get_window( parent ) : top_window;
458 if (!win || !(win->style & WS_VISIBLE)) return 0;
459 if (!win->paint_count || win->thread != thread)
460 win = find_child_to_repaint( win, thread );
461 return win ? win->handle : 0;
465 /* get the window class of a window */
466 struct window_class* get_window_class( user_handle_t window )
469 if (!(win = get_window( window ))) return NULL;
474 /* create a window */
475 DECL_HANDLER(create_window)
478 if (req->extra < 0 || req->extra > 4096) /* don't allow stupid values here */
480 set_error( STATUS_INVALID_PARAMETER );
483 if (!req->parent) /* return desktop window */
487 if (!(top_window = create_window( NULL, NULL, req->atom, req->instance, req->extra ))) return;
488 top_window->thread = NULL; /* no thread owns the desktop */
489 top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
491 reply->handle = top_window->handle;
495 struct window *win, *parent, *owner = NULL;
497 if (!(parent = get_window( req->parent ))) return;
498 if (req->owner && !(owner = get_window( req->owner ))) return;
499 if (owner == top_window) owner = NULL;
500 else if (owner && parent != top_window)
502 /* an owned window must be created as top-level */
503 set_error( STATUS_ACCESS_DENIED );
506 if (!(win = create_window( parent, owner, req->atom, req->instance, req->extra ))) return;
507 reply->handle = win->handle;
512 /* link a window into the tree */
513 DECL_HANDLER(link_window)
515 struct window *win, *parent = NULL, *previous = NULL;
517 if (!(win = get_window( req->handle ))) return;
518 if (req->parent && !(parent = get_window( req->parent ))) return;
520 if (win == top_window)
522 set_error( STATUS_INVALID_PARAMETER );
525 reply->full_parent = parent ? parent->handle : 0;
526 if (parent && req->previous)
528 if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */
530 previous = parent->last_child;
531 if (previous == win) return; /* nothing to do */
535 if (!(previous = get_window( req->previous ))) return;
536 /* previous must be a child of parent, and not win itself */
537 if (previous->parent != parent || previous == win)
539 set_error( STATUS_INVALID_PARAMETER );
544 link_window( win, parent, previous );
548 /* destroy a window */
549 DECL_HANDLER(destroy_window)
551 struct window *win = get_window( req->handle );
554 if (win != top_window) destroy_window( win );
555 else set_error( STATUS_ACCESS_DENIED );
560 /* set a window owner */
561 DECL_HANDLER(set_window_owner)
563 struct window *win = get_window( req->handle );
564 struct window *owner = NULL;
567 if (req->owner && !(owner = get_window( req->owner ))) return;
568 if (win == top_window)
570 set_error( STATUS_ACCESS_DENIED );
573 reply->prev_owner = win->owner;
574 reply->full_owner = win->owner = owner ? owner->handle : 0;
578 /* get information from a window handle */
579 DECL_HANDLER(get_window_info)
581 struct window *win = get_window( req->handle );
583 reply->full_handle = 0;
584 reply->tid = reply->pid = 0;
587 reply->full_handle = win->handle;
588 reply->last_active = win->handle;
589 if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active;
592 reply->tid = get_thread_id( win->thread );
593 reply->pid = get_process_id( win->thread->process );
594 reply->atom = get_class_atom( win->class );
600 /* set some information in a window */
601 DECL_HANDLER(set_window_info)
603 struct window *win = get_window( req->handle );
606 if (req->flags && win == top_window)
608 set_error( STATUS_ACCESS_DENIED );
611 if (req->extra_size > sizeof(req->extra_value) ||
612 req->extra_offset < -1 ||
613 req->extra_offset > win->nb_extra_bytes - (int)req->extra_size)
615 set_win32_error( ERROR_INVALID_INDEX );
618 if (req->extra_offset != -1)
620 memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, req->extra_size );
622 else if (req->flags & SET_WIN_EXTRA)
624 set_win32_error( ERROR_INVALID_INDEX );
627 reply->old_style = win->style;
628 reply->old_ex_style = win->ex_style;
629 reply->old_id = win->id;
630 reply->old_instance = win->instance;
631 reply->old_user_data = win->user_data;
632 if (req->flags & SET_WIN_STYLE) win->style = req->style;
633 if (req->flags & SET_WIN_EXSTYLE) win->ex_style = req->ex_style;
634 if (req->flags & SET_WIN_ID) win->id = req->id;
635 if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance;
636 if (req->flags & SET_WIN_USERDATA) win->user_data = req->user_data;
637 if (req->flags & SET_WIN_EXTRA) memcpy( win->extra_bytes + req->extra_offset,
638 &req->extra_value, req->extra_size );
642 /* get a list of the window parents, up to the root of the tree */
643 DECL_HANDLER(get_window_parents)
645 struct window *ptr, *win = get_window( req->handle );
650 if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
652 reply->count = total;
653 len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
654 if (len && ((data = set_reply_data_size( len ))))
656 for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
657 *data++ = ptr->handle;
662 /* get a list of the window children */
663 DECL_HANDLER(get_window_children)
665 struct window *ptr, *parent = get_window( req->parent );
671 for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next)
673 if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
674 if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
678 reply->count = total;
679 len = min( get_reply_max_size(), total * sizeof(user_handle_t) );
680 if (len && ((data = set_reply_data_size( len ))))
682 for (ptr = parent->first_child; ptr && len; ptr = ptr->next)
684 if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
685 if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
686 *data++ = ptr->handle;
687 len -= sizeof(*data);
693 /* get window tree information from a window handle */
694 DECL_HANDLER(get_window_tree)
696 struct window *win = get_window( req->handle );
702 struct window *parent = win->parent;
703 reply->parent = parent->handle;
704 reply->owner = win->owner;
705 reply->next_sibling = win->next ? win->next->handle : 0;
706 reply->prev_sibling = win->prev ? win->prev->handle : 0;
707 reply->first_sibling = parent->first_child ? parent->first_child->handle : 0;
708 reply->last_sibling = parent->last_child ? parent->last_child->handle : 0;
714 reply->next_sibling = 0;
715 reply->prev_sibling = 0;
716 reply->first_sibling = 0;
717 reply->last_sibling = 0;
719 reply->first_child = win->first_child ? win->first_child->handle : 0;
720 reply->last_child = win->last_child ? win->last_child->handle : 0;
724 /* set the window and client rectangles of a window */
725 DECL_HANDLER(set_window_rectangles)
727 struct window *win = get_window( req->handle );
731 win->window_rect = req->window;
732 win->client_rect = req->client;
737 /* get the window and client rectangles of a window */
738 DECL_HANDLER(get_window_rectangles)
740 struct window *win = get_window( req->handle );
744 reply->window = win->window_rect;
745 reply->client = win->client_rect;
750 /* get the window text */
751 DECL_HANDLER(get_window_text)
753 struct window *win = get_window( req->handle );
755 if (win && win->text)
757 size_t len = strlenW( win->text ) * sizeof(WCHAR);
758 if (len > get_reply_max_size()) len = get_reply_max_size();
759 set_reply_data( win->text, len );
764 /* set the window text */
765 DECL_HANDLER(set_window_text)
767 struct window *win = get_window( req->handle );
772 size_t len = get_req_data_size() / sizeof(WCHAR);
775 if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) return;
776 memcpy( text, get_req_data(), len * sizeof(WCHAR) );
779 if (win->text) free( win->text );
785 /* increment the window paint count */
786 DECL_HANDLER(inc_window_paint_count)
788 struct window *win = get_window( req->handle );
790 if (win && win->thread)
792 int old = win->paint_count;
793 if ((win->paint_count += req->incr) < 0) win->paint_count = 0;
794 inc_queue_paint_count( win->thread, win->paint_count - old );
799 /* get the coordinates offset between two windows */
800 DECL_HANDLER(get_windows_offset)
804 reply->x = reply->y = 0;
807 if (!(win = get_window( req->from ))) return;
810 reply->x += win->client_rect.left;
811 reply->y += win->client_rect.top;
817 if (!(win = get_window( req->to ))) return;
820 reply->x -= win->client_rect.left;
821 reply->y -= win->client_rect.top;
828 /* set a window property */
829 DECL_HANDLER(set_window_property)
831 struct window *win = get_window( req->window );
833 if (win) set_property( win, req->atom, req->handle,
834 req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM );
838 /* remove a window property */
839 DECL_HANDLER(remove_window_property)
841 struct window *win = get_window( req->window );
843 if (win) reply->handle = remove_property( win, req->atom );
847 /* get a window property */
848 DECL_HANDLER(get_window_property)
850 struct window *win = get_window( req->window );
852 if (win) reply->handle = get_property( win, req->atom );
856 /* get the list of properties of a window */
857 DECL_HANDLER(get_window_properties)
859 property_data_t *data;
860 int i, count, max = get_reply_max_size() / sizeof(*data);
861 struct window *win = get_window( req->window );
866 for (i = count = 0; i < win->prop_inuse; i++)
867 if (win->properties[i].type != PROP_TYPE_FREE) count++;
868 reply->total = count;
870 if (count > max) count = max;
871 if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) return;
873 for (i = 0; i < win->prop_inuse && count; i++)
875 if (win->properties[i].type == PROP_TYPE_FREE) continue;
876 data->atom = win->properties[i].atom;
877 data->string = (win->properties[i].type == PROP_TYPE_STRING);
878 data->handle = win->properties[i].handle;
885 /* get the new window pointer for a global window, checking permissions */
886 /* helper for set_global_windows request */
887 static int get_new_global_window( struct window **win, user_handle_t handle )
896 set_error( STATUS_ACCESS_DENIED );
899 *win = get_window( handle );
900 return (*win != NULL);
903 /* Set/get the global windows */
904 DECL_HANDLER(set_global_windows)
906 struct window *new_shell_window = shell_window;
907 struct window *new_shell_listview = shell_listview;
908 struct window *new_progman_window = progman_window;
909 struct window *new_taskman_window = taskman_window;
911 reply->old_shell_window = shell_window ? shell_window->handle : 0;
912 reply->old_shell_listview = shell_listview ? shell_listview->handle : 0;
913 reply->old_progman_window = progman_window ? progman_window->handle : 0;
914 reply->old_taskman_window = taskman_window ? taskman_window->handle : 0;
916 if (req->flags & SET_GLOBAL_SHELL_WINDOWS)
918 if (!get_new_global_window( &new_shell_window, req->shell_window )) return;
919 if (!get_new_global_window( &new_shell_listview, req->shell_listview )) return;
921 if (req->flags & SET_GLOBAL_PROGMAN_WINDOW)
923 if (!get_new_global_window( &new_progman_window, req->progman_window )) return;
925 if (req->flags & SET_GLOBAL_TASKMAN_WINDOW)
927 if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return;
929 shell_window = new_shell_window;
930 shell_listview = new_shell_listview;
931 progman_window = new_progman_window;
932 taskman_window = new_taskman_window;