Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Server-side window handling |
| 3 | * |
| 4 | * Copyright (C) 2001 Alexandre Julliard |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 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 |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 19 | */ |
| 20 | |
Alexandre Julliard | 5769d1d | 2002-04-26 19:05:15 +0000 | [diff] [blame] | 21 | #include "config.h" |
| 22 | #include "wine/port.h" |
| 23 | |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 24 | #include <assert.h> |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 25 | #include <stdarg.h> |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 26 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 27 | #include "windef.h" |
Alexandre Julliard | 47f9821 | 2001-11-14 21:28:36 +0000 | [diff] [blame] | 28 | #include "winbase.h" |
| 29 | #include "wingdi.h" |
| 30 | #include "winuser.h" |
| 31 | |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 32 | #include "object.h" |
| 33 | #include "request.h" |
| 34 | #include "thread.h" |
| 35 | #include "process.h" |
| 36 | #include "user.h" |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 37 | #include "unicode.h" |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 38 | |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 39 | /* a window property */ |
| 40 | struct property |
| 41 | { |
| 42 | unsigned short type; /* property type (see below) */ |
| 43 | atom_t atom; /* property atom */ |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 44 | obj_handle_t handle; /* property handle (user-defined storage) */ |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 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 | |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 55 | struct window |
| 56 | { |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 57 | struct window *parent; /* parent window */ |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 58 | user_handle_t owner; /* owner of this window */ |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 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 */ |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 66 | struct window_class *class; /* window class */ |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 67 | atom_t atom; /* class atom */ |
Alexandre Julliard | 5030bda | 2002-10-11 23:41:06 +0000 | [diff] [blame] | 68 | user_handle_t last_active; /* last active popup */ |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 69 | rectangle_t window_rect; /* window rectangle */ |
| 70 | rectangle_t client_rect; /* client rectangle */ |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 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 */ |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 76 | WCHAR *text; /* window caption text */ |
| 77 | int paint_count; /* count of pending paints for this window */ |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 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 */ |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 81 | int nb_extra_bytes; /* number of extra bytes */ |
| 82 | char extra_bytes[1]; /* extra bytes storage */ |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 83 | }; |
| 84 | |
| 85 | static struct window *top_window; /* top-level (desktop) window */ |
| 86 | |
Alexandre Julliard | 8d174d3 | 2003-10-07 03:40:23 +0000 | [diff] [blame] | 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; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 92 | |
| 93 | /* retrieve a pointer to a window from its handle */ |
| 94 | inline static struct window *get_window( user_handle_t handle ) |
| 95 | { |
| 96 | struct window *ret = get_user_object( handle, USER_WINDOW ); |
| 97 | if (!ret) set_error( STATUS_INVALID_HANDLE ); |
| 98 | return ret; |
| 99 | } |
| 100 | |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 101 | /* unlink a window from the tree */ |
| 102 | static void unlink_window( struct window *win ) |
| 103 | { |
| 104 | struct window *parent = win->parent; |
| 105 | |
| 106 | assert( parent ); |
| 107 | |
| 108 | if (win->next) win->next->prev = win->prev; |
| 109 | else if (parent->last_child == win) parent->last_child = win->prev; |
| 110 | |
| 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; |
| 114 | } |
| 115 | |
| 116 | |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 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 ) |
| 119 | { |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 120 | unlink_window( win ); /* unlink it from the previous location */ |
| 121 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 122 | if (parent) |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 123 | { |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 124 | win->parent = parent; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 125 | if ((win->prev = previous)) |
| 126 | { |
| 127 | if ((win->next = previous->next)) win->next->prev = win; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 128 | else if (win->parent->last_child == previous) win->parent->last_child = win; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 129 | win->prev->next = win; |
| 130 | } |
| 131 | else |
| 132 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 133 | if ((win->next = parent->first_child)) win->next->prev = win; |
| 134 | else win->parent->last_child = win; |
| 135 | parent->first_child = win; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 136 | } |
| 137 | } |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 138 | else /* move it to parent unlinked list */ |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 139 | { |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 140 | parent = win->parent; |
| 141 | if ((win->next = parent->first_unlinked)) win->next->prev = win; |
| 142 | win->prev = NULL; |
| 143 | parent->first_unlinked = win; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 144 | } |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 145 | } |
| 146 | |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 147 | /* set a window property */ |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 148 | static void set_property( struct window *win, atom_t atom, obj_handle_t handle, |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 149 | enum property_type type ) |
| 150 | { |
| 151 | int i, free = -1; |
| 152 | struct property *new_props; |
| 153 | |
| 154 | /* check if it exists already */ |
| 155 | for (i = 0; i < win->prop_inuse; i++) |
| 156 | { |
| 157 | if (win->properties[i].type == PROP_TYPE_FREE) |
| 158 | { |
| 159 | free = i; |
| 160 | continue; |
| 161 | } |
| 162 | if (win->properties[i].atom == atom) |
| 163 | { |
| 164 | win->properties[i].type = type; |
| 165 | win->properties[i].handle = handle; |
| 166 | return; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /* need to add an entry */ |
| 171 | if (!grab_global_atom( atom )) return; |
| 172 | if (free == -1) |
| 173 | { |
| 174 | /* no free entry */ |
| 175 | if (win->prop_inuse >= win->prop_alloc) |
| 176 | { |
| 177 | /* need to grow the array */ |
| 178 | if (!(new_props = realloc( win->properties, |
| 179 | sizeof(*new_props) * (win->prop_alloc + 16) ))) |
| 180 | { |
| 181 | set_error( STATUS_NO_MEMORY ); |
| 182 | release_global_atom( atom ); |
| 183 | return; |
| 184 | } |
| 185 | win->prop_alloc += 16; |
| 186 | win->properties = new_props; |
| 187 | } |
| 188 | free = win->prop_inuse++; |
| 189 | } |
| 190 | win->properties[free].atom = atom; |
| 191 | win->properties[free].type = type; |
| 192 | win->properties[free].handle = handle; |
| 193 | } |
| 194 | |
| 195 | /* remove a window property */ |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 196 | static obj_handle_t remove_property( struct window *win, atom_t atom ) |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 197 | { |
| 198 | int i; |
| 199 | |
| 200 | for (i = 0; i < win->prop_inuse; i++) |
| 201 | { |
| 202 | if (win->properties[i].type == PROP_TYPE_FREE) continue; |
| 203 | if (win->properties[i].atom == atom) |
| 204 | { |
| 205 | release_global_atom( atom ); |
| 206 | win->properties[i].type = PROP_TYPE_FREE; |
| 207 | return win->properties[i].handle; |
| 208 | } |
| 209 | } |
| 210 | /* FIXME: last error? */ |
| 211 | return 0; |
| 212 | } |
| 213 | |
| 214 | /* find a window property */ |
Alexandre Julliard | 5188574 | 2002-05-30 20:12:58 +0000 | [diff] [blame] | 215 | static obj_handle_t get_property( struct window *win, atom_t atom ) |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 216 | { |
| 217 | int i; |
| 218 | |
| 219 | for (i = 0; i < win->prop_inuse; i++) |
| 220 | { |
| 221 | if (win->properties[i].type == PROP_TYPE_FREE) continue; |
| 222 | if (win->properties[i].atom == atom) return win->properties[i].handle; |
| 223 | } |
| 224 | /* FIXME: last error? */ |
| 225 | return 0; |
| 226 | } |
| 227 | |
| 228 | /* destroy all properties of a window */ |
| 229 | inline static void destroy_properties( struct window *win ) |
| 230 | { |
| 231 | int i; |
| 232 | |
| 233 | if (!win->properties) return; |
| 234 | for (i = 0; i < win->prop_inuse; i++) |
| 235 | { |
| 236 | if (win->properties[i].type == PROP_TYPE_FREE) continue; |
| 237 | release_global_atom( win->properties[i].atom ); |
| 238 | } |
| 239 | free( win->properties ); |
| 240 | } |
| 241 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 242 | /* destroy a window */ |
| 243 | static void destroy_window( struct window *win ) |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 244 | { |
| 245 | assert( win != top_window ); |
| 246 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 247 | /* destroy all children */ |
| 248 | while (win->first_child) destroy_window( win->first_child ); |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 249 | while (win->first_unlinked) destroy_window( win->first_unlinked ); |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 250 | |
Alexandre Julliard | e806c97 | 2001-11-24 03:44:47 +0000 | [diff] [blame] | 251 | if (win->thread->queue) |
| 252 | { |
| 253 | if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count ); |
| 254 | queue_cleanup_window( win->thread, win->handle ); |
| 255 | } |
Alexandre Julliard | 8d174d3 | 2003-10-07 03:40:23 +0000 | [diff] [blame] | 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; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 261 | free_user_handle( win->handle ); |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 262 | destroy_properties( win ); |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 263 | unlink_window( win ); |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 264 | release_class( win->class ); |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 265 | if (win->text) free( win->text ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 266 | memset( win, 0x55, sizeof(*win) ); |
| 267 | free( win ); |
| 268 | } |
| 269 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 270 | /* create a new window structure (note: the window is not linked in the window tree) */ |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 271 | static struct window *create_window( struct window *parent, struct window *owner, |
| 272 | atom_t atom, void *instance ) |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 273 | { |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 274 | int extra_bytes; |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 275 | struct window *win; |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 276 | struct window_class *class = grab_class( current->process, atom, instance, &extra_bytes ); |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 277 | |
| 278 | if (!class) return NULL; |
| 279 | |
| 280 | win = mem_alloc( sizeof(*win) + extra_bytes - 1 ); |
| 281 | if (!win) |
| 282 | { |
| 283 | release_class( class ); |
| 284 | return NULL; |
| 285 | } |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 286 | |
| 287 | if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) |
| 288 | { |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 289 | release_class( class ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 290 | free( win ); |
| 291 | return NULL; |
| 292 | } |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 293 | win->parent = parent; |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 294 | win->owner = owner ? owner->handle : 0; |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 295 | win->first_child = NULL; |
| 296 | win->last_child = NULL; |
| 297 | win->first_unlinked = NULL; |
| 298 | win->thread = current; |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 299 | win->class = class; |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 300 | win->atom = atom; |
Alexandre Julliard | 5030bda | 2002-10-11 23:41:06 +0000 | [diff] [blame] | 301 | win->last_active = win->handle; |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 302 | win->style = 0; |
| 303 | win->ex_style = 0; |
| 304 | win->id = 0; |
| 305 | win->instance = NULL; |
| 306 | win->user_data = NULL; |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 307 | win->text = NULL; |
| 308 | win->paint_count = 0; |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 309 | win->prop_inuse = 0; |
| 310 | win->prop_alloc = 0; |
| 311 | win->properties = NULL; |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 312 | win->nb_extra_bytes = extra_bytes; |
| 313 | memset( win->extra_bytes, 0, extra_bytes ); |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 314 | |
| 315 | if (parent) /* put it on parent unlinked list */ |
| 316 | { |
| 317 | if ((win->next = parent->first_unlinked)) win->next->prev = win; |
| 318 | win->prev = NULL; |
| 319 | parent->first_unlinked = win; |
| 320 | } |
| 321 | else win->next = win->prev = NULL; |
| 322 | |
Alexandre Julliard | ab5063b | 2002-10-11 18:50:15 +0000 | [diff] [blame] | 323 | /* if parent belongs to a different thread, attach the two threads */ |
| 324 | if (parent && parent->thread && parent->thread != current) |
| 325 | attach_thread_input( current, parent->thread ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 326 | return win; |
| 327 | } |
| 328 | |
| 329 | /* destroy all windows belonging to a given thread */ |
| 330 | void destroy_thread_windows( struct thread *thread ) |
| 331 | { |
| 332 | user_handle_t handle = 0; |
| 333 | struct window *win; |
| 334 | |
| 335 | while ((win = next_user_handle( &handle, USER_WINDOW ))) |
| 336 | { |
| 337 | if (win->thread != thread) continue; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 338 | destroy_window( win ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 339 | } |
| 340 | } |
| 341 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 342 | /* check whether child is a descendant of parent */ |
| 343 | int is_child_window( user_handle_t parent, user_handle_t child ) |
| 344 | { |
| 345 | struct window *child_ptr = get_user_object( child, USER_WINDOW ); |
| 346 | struct window *parent_ptr = get_user_object( parent, USER_WINDOW ); |
| 347 | |
| 348 | if (!child_ptr || !parent_ptr) return 0; |
| 349 | while (child_ptr->parent) |
| 350 | { |
| 351 | if (child_ptr->parent == parent_ptr) return 1; |
| 352 | child_ptr = child_ptr->parent; |
| 353 | } |
| 354 | return 0; |
| 355 | } |
| 356 | |
Alexandre Julliard | 5030bda | 2002-10-11 23:41:06 +0000 | [diff] [blame] | 357 | /* check whether window is a top-level window */ |
| 358 | int is_top_level_window( user_handle_t window ) |
| 359 | { |
| 360 | struct window *win = get_user_object( window, USER_WINDOW ); |
| 361 | return (win && win->parent == top_window); |
| 362 | } |
| 363 | |
| 364 | /* make a window active if possible */ |
| 365 | int make_window_active( user_handle_t window ) |
| 366 | { |
| 367 | struct window *owner, *win = get_window( window ); |
| 368 | |
| 369 | if (!win) return 0; |
| 370 | |
| 371 | /* set last active for window and its owner */ |
| 372 | win->last_active = win->handle; |
| 373 | if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle; |
| 374 | return 1; |
| 375 | } |
| 376 | |
Alexandre Julliard | 242e395 | 2003-01-08 00:27:58 +0000 | [diff] [blame] | 377 | /* find child of 'parent' that contains the given point (in parent-relative coords) */ |
| 378 | static struct window *child_window_from_point( struct window *parent, int x, int y ) |
| 379 | { |
Alexandre Julliard | 3783e49 | 2003-01-08 19:55:08 +0000 | [diff] [blame] | 380 | struct window *ptr; |
Alexandre Julliard | 242e395 | 2003-01-08 00:27:58 +0000 | [diff] [blame] | 381 | |
Alexandre Julliard | 3783e49 | 2003-01-08 19:55:08 +0000 | [diff] [blame] | 382 | for (ptr = parent->first_child; ptr; ptr = ptr->next) |
Alexandre Julliard | 242e395 | 2003-01-08 00:27:58 +0000 | [diff] [blame] | 383 | { |
| 384 | if (!(ptr->style & WS_VISIBLE)) continue; /* not visible -> skip */ |
| 385 | if ((ptr->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED)) |
| 386 | continue; /* disabled child -> skip */ |
| 387 | if ((ptr->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT)) |
| 388 | continue; /* transparent -> skip */ |
| 389 | if (x < ptr->window_rect.left || x >= ptr->window_rect.right || |
| 390 | y < ptr->window_rect.top || y >= ptr->window_rect.bottom) |
| 391 | continue; /* not in window -> skip */ |
| 392 | |
| 393 | /* FIXME: check window region here */ |
| 394 | |
| 395 | /* if window is minimized or disabled, return at once */ |
| 396 | if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr; |
| 397 | |
| 398 | /* if point is not in client area, return at once */ |
| 399 | if (x < ptr->client_rect.left || x >= ptr->client_rect.right || |
| 400 | y < ptr->client_rect.top || y >= ptr->client_rect.bottom) |
| 401 | return ptr; |
| 402 | |
| 403 | return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top ); |
| 404 | } |
| 405 | return parent; /* not found any child */ |
| 406 | } |
| 407 | |
| 408 | /* find window containing point (in absolute coords) */ |
| 409 | user_handle_t window_from_point( int x, int y ) |
| 410 | { |
| 411 | struct window *ret; |
| 412 | |
| 413 | if (!top_window) return 0; |
| 414 | ret = child_window_from_point( top_window, x, y ); |
| 415 | return ret->handle; |
| 416 | } |
Alexandre Julliard | 5030bda | 2002-10-11 23:41:06 +0000 | [diff] [blame] | 417 | |
Alexandre Julliard | 81f2a73 | 2002-03-23 20:43:52 +0000 | [diff] [blame] | 418 | /* return the thread owning a window */ |
| 419 | struct thread *get_window_thread( user_handle_t handle ) |
| 420 | { |
| 421 | struct window *win = get_user_object( handle, USER_WINDOW ); |
| 422 | if (!win || !win->thread) return NULL; |
| 423 | return (struct thread *)grab_object( win->thread ); |
| 424 | } |
Alexandre Julliard | 47f9821 | 2001-11-14 21:28:36 +0000 | [diff] [blame] | 425 | |
| 426 | /* find a child of the specified window that needs repainting */ |
| 427 | static struct window *find_child_to_repaint( struct window *parent, struct thread *thread ) |
| 428 | { |
| 429 | struct window *ptr, *ret = NULL; |
| 430 | |
| 431 | for (ptr = parent->first_child; ptr && !ret; ptr = ptr->next) |
| 432 | { |
| 433 | if (!(ptr->style & WS_VISIBLE)) continue; |
| 434 | if (ptr->paint_count && ptr->thread == thread) |
| 435 | ret = ptr; |
| 436 | else /* explore its children */ |
| 437 | ret = find_child_to_repaint( ptr, thread ); |
| 438 | } |
| 439 | |
| 440 | if (ret && (ret->ex_style & WS_EX_TRANSPARENT)) |
| 441 | { |
| 442 | /* transparent window, check for non-transparent sibling to paint first */ |
| 443 | for (ptr = ret->next; ptr; ptr = ptr->next) |
| 444 | { |
| 445 | if (!(ptr->style & WS_VISIBLE)) continue; |
| 446 | if (ptr->ex_style & WS_EX_TRANSPARENT) continue; |
| 447 | if (ptr->paint_count && ptr->thread == thread) return ptr; |
| 448 | } |
| 449 | } |
| 450 | return ret; |
| 451 | } |
| 452 | |
| 453 | |
| 454 | /* find a window that needs repainting */ |
| 455 | user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ) |
| 456 | { |
| 457 | struct window *win = parent ? get_window( parent ) : top_window; |
| 458 | |
| 459 | if (!win || !(win->style & WS_VISIBLE)) return 0; |
| 460 | if (!win->paint_count || win->thread != thread) |
| 461 | win = find_child_to_repaint( win, thread ); |
| 462 | return win ? win->handle : 0; |
| 463 | } |
| 464 | |
| 465 | |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 466 | /* get the window class of a window */ |
| 467 | struct window_class* get_window_class( user_handle_t window ) |
| 468 | { |
| 469 | struct window *win; |
| 470 | if (!(win = get_window( window ))) return NULL; |
| 471 | return win->class; |
| 472 | } |
| 473 | |
| 474 | |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 475 | /* create a window */ |
| 476 | DECL_HANDLER(create_window) |
| 477 | { |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 478 | struct window *win; |
| 479 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 480 | reply->handle = 0; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 481 | if (!req->parent) /* return desktop window */ |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 482 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 483 | if (!top_window) |
| 484 | { |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 485 | if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 486 | top_window->thread = NULL; /* no thread owns the desktop */ |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 487 | top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 488 | } |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 489 | win = top_window; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 490 | } |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 491 | else |
| 492 | { |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 493 | struct window *parent, *owner = NULL; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 494 | |
| 495 | if (!(parent = get_window( req->parent ))) return; |
| 496 | if (req->owner && !(owner = get_window( req->owner ))) return; |
Alexandre Julliard | 4a9c839 | 2001-11-06 17:54:15 +0000 | [diff] [blame] | 497 | if (owner == top_window) owner = NULL; |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 498 | else if (owner && parent != top_window) |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 499 | { |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 500 | /* an owned window must be created as top-level */ |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 501 | set_error( STATUS_ACCESS_DENIED ); |
| 502 | return; |
| 503 | } |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 504 | if (!(win = create_window( parent, owner, req->atom, req->instance ))) return; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 505 | } |
Alexandre Julliard | bd13ab8 | 2003-12-11 05:34:53 +0000 | [diff] [blame] | 506 | reply->handle = win->handle; |
| 507 | reply->extra = win->nb_extra_bytes; |
| 508 | reply->class_ptr = get_class_client_ptr( win->class ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | |
| 512 | /* link a window into the tree */ |
| 513 | DECL_HANDLER(link_window) |
| 514 | { |
| 515 | struct window *win, *parent = NULL, *previous = NULL; |
| 516 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 517 | if (!(win = get_window( req->handle ))) return; |
| 518 | if (req->parent && !(parent = get_window( req->parent ))) return; |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 519 | |
| 520 | if (win == top_window) |
| 521 | { |
| 522 | set_error( STATUS_INVALID_PARAMETER ); |
| 523 | return; |
| 524 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 525 | reply->full_parent = parent ? parent->handle : 0; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 526 | if (parent && req->previous) |
| 527 | { |
Alexandre Julliard | 5af055d | 2001-09-24 01:13:48 +0000 | [diff] [blame] | 528 | if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */ |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 529 | { |
Alexandre Julliard | 5af055d | 2001-09-24 01:13:48 +0000 | [diff] [blame] | 530 | previous = parent->last_child; |
| 531 | if (previous == win) return; /* nothing to do */ |
| 532 | } |
| 533 | else |
| 534 | { |
| 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) |
| 538 | { |
| 539 | set_error( STATUS_INVALID_PARAMETER ); |
| 540 | return; |
| 541 | } |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 542 | } |
| 543 | } |
| 544 | link_window( win, parent, previous ); |
| 545 | } |
| 546 | |
| 547 | |
| 548 | /* destroy a window */ |
| 549 | DECL_HANDLER(destroy_window) |
| 550 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 551 | struct window *win = get_window( req->handle ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 552 | if (win) |
| 553 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 554 | if (win != top_window) destroy_window( win ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 555 | else set_error( STATUS_ACCESS_DENIED ); |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 560 | /* set a window owner */ |
| 561 | DECL_HANDLER(set_window_owner) |
| 562 | { |
| 563 | struct window *win = get_window( req->handle ); |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 564 | struct window *owner = NULL; |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 565 | |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 566 | if (!win) return; |
| 567 | if (req->owner && !(owner = get_window( req->owner ))) return; |
| 568 | if (win == top_window) |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 569 | { |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 570 | set_error( STATUS_ACCESS_DENIED ); |
| 571 | return; |
| 572 | } |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 573 | reply->prev_owner = win->owner; |
| 574 | reply->full_owner = win->owner = owner ? owner->handle : 0; |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 575 | } |
| 576 | |
| 577 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 578 | /* get information from a window handle */ |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 579 | DECL_HANDLER(get_window_info) |
| 580 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 581 | struct window *win = get_window( req->handle ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 582 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 583 | reply->full_handle = 0; |
| 584 | reply->tid = reply->pid = 0; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 585 | if (win) |
| 586 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 587 | reply->full_handle = win->handle; |
Alexandre Julliard | 5030bda | 2002-10-11 23:41:06 +0000 | [diff] [blame] | 588 | reply->last_active = win->handle; |
| 589 | if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active; |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 590 | if (win->thread) |
| 591 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 592 | reply->tid = get_thread_id( win->thread ); |
| 593 | reply->pid = get_process_id( win->thread->process ); |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 594 | reply->atom = get_class_atom( win->class ); |
Alexandre Julliard | 1a66d22 | 2001-08-28 18:44:52 +0000 | [diff] [blame] | 595 | } |
| 596 | } |
| 597 | } |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 598 | |
| 599 | |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 600 | /* set some information in a window */ |
| 601 | DECL_HANDLER(set_window_info) |
| 602 | { |
| 603 | struct window *win = get_window( req->handle ); |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 604 | |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 605 | if (!win) return; |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 606 | if (req->flags && win == top_window) |
| 607 | { |
| 608 | set_error( STATUS_ACCESS_DENIED ); |
| 609 | return; |
| 610 | } |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 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) |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 614 | { |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 615 | set_win32_error( ERROR_INVALID_INDEX ); |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 616 | return; |
| 617 | } |
| 618 | if (req->extra_offset != -1) |
| 619 | { |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 620 | memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, req->extra_size ); |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 621 | } |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 622 | else if (req->flags & SET_WIN_EXTRA) |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 623 | { |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 624 | set_win32_error( ERROR_INVALID_INDEX ); |
Alexandre Julliard | 97903d2 | 2003-11-26 22:15:41 +0000 | [diff] [blame] | 625 | return; |
| 626 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 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; |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 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; |
Alexandre Julliard | ebf1243 | 2003-12-10 01:34:51 +0000 | [diff] [blame] | 637 | if (req->flags & SET_WIN_EXTRA) memcpy( win->extra_bytes + req->extra_offset, |
| 638 | &req->extra_value, req->extra_size ); |
Alexandre Julliard | ddc3317 | 2001-10-22 19:08:33 +0000 | [diff] [blame] | 639 | } |
| 640 | |
| 641 | |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 642 | /* get a list of the window parents, up to the root of the tree */ |
| 643 | DECL_HANDLER(get_window_parents) |
| 644 | { |
| 645 | struct window *ptr, *win = get_window( req->handle ); |
| 646 | int total = 0; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 647 | user_handle_t *data; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 648 | size_t len; |
| 649 | |
| 650 | if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++; |
| 651 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 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 )))) |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 655 | { |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 656 | for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data)) |
| 657 | *data++ = ptr->handle; |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | |
| 662 | /* get a list of the window children */ |
| 663 | DECL_HANDLER(get_window_children) |
| 664 | { |
| 665 | struct window *ptr, *parent = get_window( req->parent ); |
| 666 | int total = 0; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 667 | user_handle_t *data; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 668 | size_t len; |
| 669 | |
| 670 | if (parent) |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 671 | for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) |
| 672 | { |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 673 | if (req->atom && get_class_atom(ptr->class) != req->atom) continue; |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 674 | if (req->tid && get_thread_id(ptr->thread) != req->tid) continue; |
| 675 | total++; |
| 676 | } |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 677 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 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 )))) |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 681 | { |
Uwe Bonnes | 4f7d893 | 2002-04-11 17:32:10 +0000 | [diff] [blame] | 682 | for (ptr = parent->first_child; ptr && len; ptr = ptr->next) |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 683 | { |
Alexandre Julliard | bfce151 | 2003-12-10 04:08:06 +0000 | [diff] [blame] | 684 | if (req->atom && get_class_atom(ptr->class) != req->atom) continue; |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 685 | if (req->tid && get_thread_id(ptr->thread) != req->tid) continue; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 686 | *data++ = ptr->handle; |
Uwe Bonnes | 4f7d893 | 2002-04-11 17:32:10 +0000 | [diff] [blame] | 687 | len -= sizeof(*data); |
Alexandre Julliard | 844ceb9 | 2001-10-09 23:26:40 +0000 | [diff] [blame] | 688 | } |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 689 | } |
| 690 | } |
| 691 | |
| 692 | |
| 693 | /* get window tree information from a window handle */ |
| 694 | DECL_HANDLER(get_window_tree) |
| 695 | { |
| 696 | struct window *win = get_window( req->handle ); |
| 697 | |
| 698 | if (!win) return; |
| 699 | |
| 700 | if (win->parent) |
| 701 | { |
| 702 | struct window *parent = win->parent; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 703 | reply->parent = parent->handle; |
Alexandre Julliard | 7dafa61 | 2002-09-25 00:21:56 +0000 | [diff] [blame] | 704 | reply->owner = win->owner; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 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; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 709 | } |
| 710 | else |
| 711 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 712 | reply->parent = 0; |
| 713 | reply->owner = 0; |
| 714 | reply->next_sibling = 0; |
| 715 | reply->prev_sibling = 0; |
| 716 | reply->first_sibling = 0; |
| 717 | reply->last_sibling = 0; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 718 | } |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 719 | reply->first_child = win->first_child ? win->first_child->handle : 0; |
| 720 | reply->last_child = win->last_child ? win->last_child->handle : 0; |
Alexandre Julliard | a09da0c | 2001-09-21 21:08:40 +0000 | [diff] [blame] | 721 | } |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 722 | |
| 723 | |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 724 | /* set the window and client rectangles of a window */ |
| 725 | DECL_HANDLER(set_window_rectangles) |
| 726 | { |
| 727 | struct window *win = get_window( req->handle ); |
| 728 | |
| 729 | if (win) |
| 730 | { |
| 731 | win->window_rect = req->window; |
| 732 | win->client_rect = req->client; |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | |
| 737 | /* get the window and client rectangles of a window */ |
| 738 | DECL_HANDLER(get_window_rectangles) |
| 739 | { |
| 740 | struct window *win = get_window( req->handle ); |
| 741 | |
| 742 | if (win) |
| 743 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 744 | reply->window = win->window_rect; |
| 745 | reply->client = win->client_rect; |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 746 | } |
| 747 | } |
| 748 | |
| 749 | |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 750 | /* get the window text */ |
| 751 | DECL_HANDLER(get_window_text) |
| 752 | { |
| 753 | struct window *win = get_window( req->handle ); |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 754 | |
| 755 | if (win && win->text) |
| 756 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 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 ); |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 760 | } |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 761 | } |
| 762 | |
| 763 | |
| 764 | /* set the window text */ |
| 765 | DECL_HANDLER(set_window_text) |
| 766 | { |
| 767 | struct window *win = get_window( req->handle ); |
| 768 | |
| 769 | if (win) |
| 770 | { |
| 771 | WCHAR *text = NULL; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 772 | size_t len = get_req_data_size() / sizeof(WCHAR); |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 773 | if (len) |
| 774 | { |
| 775 | if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) return; |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 776 | memcpy( text, get_req_data(), len * sizeof(WCHAR) ); |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 777 | text[len] = 0; |
| 778 | } |
| 779 | if (win->text) free( win->text ); |
| 780 | win->text = text; |
| 781 | } |
| 782 | } |
| 783 | |
| 784 | |
| 785 | /* increment the window paint count */ |
| 786 | DECL_HANDLER(inc_window_paint_count) |
| 787 | { |
| 788 | struct window *win = get_window( req->handle ); |
| 789 | |
Alexandre Julliard | 47f9821 | 2001-11-14 21:28:36 +0000 | [diff] [blame] | 790 | if (win && win->thread) |
Alexandre Julliard | 805bdc5 | 2001-11-13 22:23:48 +0000 | [diff] [blame] | 791 | { |
| 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 ); |
| 795 | } |
| 796 | } |
| 797 | |
| 798 | |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 799 | /* get the coordinates offset between two windows */ |
| 800 | DECL_HANDLER(get_windows_offset) |
| 801 | { |
| 802 | struct window *win; |
| 803 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 804 | reply->x = reply->y = 0; |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 805 | if (req->from) |
| 806 | { |
| 807 | if (!(win = get_window( req->from ))) return; |
| 808 | while (win) |
| 809 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 810 | reply->x += win->client_rect.left; |
| 811 | reply->y += win->client_rect.top; |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 812 | win = win->parent; |
| 813 | } |
| 814 | } |
| 815 | if (req->to) |
| 816 | { |
| 817 | if (!(win = get_window( req->to ))) return; |
| 818 | while (win) |
| 819 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 820 | reply->x -= win->client_rect.left; |
| 821 | reply->y -= win->client_rect.top; |
Alexandre Julliard | 0d50965 | 2001-10-16 21:55:37 +0000 | [diff] [blame] | 822 | win = win->parent; |
| 823 | } |
| 824 | } |
| 825 | } |
| 826 | |
| 827 | |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 828 | /* set a window property */ |
| 829 | DECL_HANDLER(set_window_property) |
| 830 | { |
| 831 | struct window *win = get_window( req->window ); |
| 832 | |
| 833 | if (win) set_property( win, req->atom, req->handle, |
| 834 | req->string ? PROP_TYPE_STRING : PROP_TYPE_ATOM ); |
| 835 | } |
| 836 | |
| 837 | |
| 838 | /* remove a window property */ |
| 839 | DECL_HANDLER(remove_window_property) |
| 840 | { |
| 841 | struct window *win = get_window( req->window ); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 842 | reply->handle = 0; |
| 843 | if (win) reply->handle = remove_property( win, req->atom ); |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 844 | } |
| 845 | |
| 846 | |
| 847 | /* get a window property */ |
| 848 | DECL_HANDLER(get_window_property) |
| 849 | { |
| 850 | struct window *win = get_window( req->window ); |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 851 | reply->handle = 0; |
| 852 | if (win) reply->handle = get_property( win, req->atom ); |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 853 | } |
| 854 | |
| 855 | |
| 856 | /* get the list of properties of a window */ |
| 857 | DECL_HANDLER(get_window_properties) |
| 858 | { |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 859 | property_data_t *data; |
| 860 | int i, count, max = get_reply_max_size() / sizeof(*data); |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 861 | struct window *win = get_window( req->window ); |
| 862 | |
Alexandre Julliard | 9caa71e | 2001-11-30 18:46:42 +0000 | [diff] [blame] | 863 | reply->total = 0; |
| 864 | if (!win) return; |
| 865 | |
| 866 | for (i = count = 0; i < win->prop_inuse; i++) |
| 867 | if (win->properties[i].type != PROP_TYPE_FREE) count++; |
| 868 | reply->total = count; |
| 869 | |
| 870 | if (count > max) count = max; |
| 871 | if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) return; |
| 872 | |
| 873 | for (i = 0; i < win->prop_inuse && count; i++) |
| 874 | { |
| 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; |
| 879 | data++; |
| 880 | count--; |
| 881 | } |
Alexandre Julliard | 7a2017d | 2001-10-12 19:10:26 +0000 | [diff] [blame] | 882 | } |
Alexandre Julliard | 8d174d3 | 2003-10-07 03:40:23 +0000 | [diff] [blame] | 883 | |
| 884 | |
| 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 ) |
| 888 | { |
Alexandre Julliard | 8d174d3 | 2003-10-07 03:40:23 +0000 | [diff] [blame] | 889 | if (!handle) |
| 890 | { |
| 891 | *win = NULL; |
| 892 | return 1; |
| 893 | } |
Martin Fuchs | 76adb1f | 2003-11-18 00:13:34 +0000 | [diff] [blame] | 894 | else if (*win) |
| 895 | { |
| 896 | set_error( STATUS_ACCESS_DENIED ); |
| 897 | return 0; |
| 898 | } |
Alexandre Julliard | 8d174d3 | 2003-10-07 03:40:23 +0000 | [diff] [blame] | 899 | *win = get_window( handle ); |
| 900 | return (*win != NULL); |
| 901 | } |
| 902 | |
| 903 | /* Set/get the global windows */ |
| 904 | DECL_HANDLER(set_global_windows) |
| 905 | { |
| 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; |
| 910 | |
| 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; |
| 915 | |
| 916 | if (req->flags & SET_GLOBAL_SHELL_WINDOWS) |
| 917 | { |
| 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; |
| 920 | } |
| 921 | if (req->flags & SET_GLOBAL_PROGMAN_WINDOW) |
| 922 | { |
| 923 | if (!get_new_global_window( &new_progman_window, req->progman_window )) return; |
| 924 | } |
| 925 | if (req->flags & SET_GLOBAL_TASKMAN_WINDOW) |
| 926 | { |
| 927 | if (!get_new_global_window( &new_taskman_window, req->taskman_window )) return; |
| 928 | } |
| 929 | shell_window = new_shell_window; |
| 930 | shell_listview = new_shell_listview; |
| 931 | progman_window = new_progman_window; |
| 932 | taskman_window = new_taskman_window; |
| 933 | } |