image: port to new class system
[awesome.git] / property.c
blob1773fb07a7ce1cd75ba4ed1a976f273becf23dd9
1 /*
2 * property.c - property handlers
4 * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <xcb/xcb_atom.h>
24 #include "screen.h"
25 #include "property.h"
26 #include "client.h"
27 #include "ewmh.h"
28 #include "wibox.h"
29 #include "window.h"
30 #include "luaa.h"
31 #include "common/atoms.h"
32 #include "common/xutil.h"
34 void
35 property_update_wm_transient_for(client_t *c, xcb_get_property_reply_t *reply)
37 xcb_window_t trans;
39 if(reply)
41 if(!xcb_get_wm_transient_for_from_reply(&trans, reply))
42 return;
44 else
46 if(!xcb_get_wm_transient_for_reply(globalconf.connection,
47 xcb_get_wm_transient_for_unchecked(globalconf.connection,
48 c->win),
49 &trans, NULL))
50 return;
53 c->type = WINDOW_TYPE_DIALOG;
54 c->transient_for = client_getbywin(trans);
55 client_setabove(c, false);
58 static int
59 property_handle_wm_transient_for(void *data,
60 xcb_connection_t *connection,
61 uint8_t state,
62 xcb_window_t window,
63 xcb_atom_t name,
64 xcb_get_property_reply_t *reply)
66 client_t *c = client_getbywin(window);
68 if(c)
69 property_update_wm_transient_for(c, reply);
71 return 0;
74 void
75 property_update_wm_client_machine(client_t *c)
77 ssize_t slen;
78 char *value;
80 if(!xutil_text_prop_get(globalconf.connection, c->win,
81 WM_CLIENT_MACHINE, &value, &slen))
82 return;
84 p_delete(&c->machine);
85 c->machine = a_strdup(value);
88 static int
89 property_handle_wm_client_machine(void *data,
90 xcb_connection_t *connection,
91 uint8_t state,
92 xcb_window_t window,
93 xcb_atom_t name,
94 xcb_get_property_reply_t *reply)
96 client_t *c = client_getbywin(window);
98 if(c)
99 property_update_wm_client_machine(c);
101 return 0;
104 void
105 property_update_wm_window_role(client_t *c)
107 ssize_t slen;
108 char *value;
110 if(!xutil_text_prop_get(globalconf.connection, c->win,
111 WM_WINDOW_ROLE, &value, &slen))
112 return;
114 p_delete(&c->role);
115 c->role = a_strdup(value);
118 static int
119 property_handle_wm_window_role(void *data,
120 xcb_connection_t *connection,
121 uint8_t state,
122 xcb_window_t window,
123 xcb_atom_t name,
124 xcb_get_property_reply_t *reply)
126 client_t *c = client_getbywin(window);
128 if(c)
129 property_update_wm_window_role(c);
131 return 0;
134 /** Update leader hint of a client.
135 * \param c The client.
136 * \param reply (Optional) An existing reply.
138 void
139 property_update_wm_client_leader(client_t *c, xcb_get_property_reply_t *reply)
141 xcb_get_property_cookie_t client_leader_q;
142 void *data;
143 bool no_reply = !reply;
145 if(no_reply)
147 client_leader_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
148 WM_CLIENT_LEADER, WINDOW, 0, 32);
150 reply = xcb_get_property_reply(globalconf.connection, client_leader_q, NULL);
153 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
154 c->leader_win = *(xcb_window_t *) data;
156 /* Only free when we created a reply ourselves. */
157 if(no_reply)
158 p_delete(&reply);
161 static int
162 property_handle_wm_client_leader(void *data,
163 xcb_connection_t *connection,
164 uint8_t state,
165 xcb_window_t window,
166 xcb_atom_t name,
167 xcb_get_property_reply_t *reply)
169 client_t *c = client_getbywin(window);
171 if(c)
172 property_update_wm_client_leader(c, reply);
174 return 0;
177 /** Update the size hints of a client.
178 * \param c The client.
179 * \param reply (Optional) An existing reply.
181 void
182 property_update_wm_normal_hints(client_t *c, xcb_get_property_reply_t *reply)
184 if(reply)
186 if(!xcb_get_wm_size_hints_from_reply(&c->size_hints, reply))
187 return;
189 else
191 if(!xcb_get_wm_normal_hints_reply(globalconf.connection,
192 xcb_get_wm_normal_hints_unchecked(globalconf.connection,
193 c->win),
194 &c->size_hints, NULL))
195 return;
199 static int
200 property_handle_wm_normal_hints(void *data,
201 xcb_connection_t *connection,
202 uint8_t state,
203 xcb_window_t window,
204 xcb_atom_t name,
205 xcb_get_property_reply_t *reply)
207 client_t *c = client_getbywin(window);
209 if(c)
210 property_update_wm_normal_hints(c, reply);
212 return 0;
215 /** Update the WM hints of a client.
216 * \param c The client.
217 * \param reply (Optional) An existing reply.
219 void
220 property_update_wm_hints(client_t *c, xcb_get_property_reply_t *reply)
222 xcb_wm_hints_t wmh;
224 if(reply)
226 if(!xcb_get_wm_hints_from_reply(&wmh, reply))
227 return;
229 else
231 if(!xcb_get_wm_hints_reply(globalconf.connection,
232 xcb_get_wm_hints_unchecked(globalconf.connection, c->win),
233 &wmh, NULL))
234 return;
237 bool isurgent = xcb_wm_hints_get_urgency(&wmh);
238 client_seturgent(c, isurgent);
239 if(wmh.flags & XCB_WM_HINT_STATE &&
240 wmh.initial_state == XCB_WM_STATE_WITHDRAWN)
241 client_setborder(c, 0);
243 if(wmh.flags & XCB_WM_HINT_INPUT)
244 c->nofocus = !wmh.input;
246 if(wmh.flags & XCB_WM_HINT_WINDOW_GROUP)
247 c->group_win = wmh.window_group;
250 static int
251 property_handle_wm_hints(void *data,
252 xcb_connection_t *connection,
253 uint8_t state,
254 xcb_window_t window,
255 xcb_atom_t name,
256 xcb_get_property_reply_t *reply)
258 client_t *c = client_getbywin(window);
260 if(c)
261 property_update_wm_hints(c, reply);
263 return 0;
266 /** Update client name attribute with its new title.
267 * \param c The client.
269 void
270 property_update_wm_name(client_t *c)
272 char *name;
273 ssize_t len;
275 if(!xutil_text_prop_get(globalconf.connection, c->win, _NET_WM_NAME, &name, &len))
276 if(!xutil_text_prop_get(globalconf.connection, c->win, WM_NAME, &name, &len))
277 return;
279 p_delete(&c->name);
281 c->name = name;
283 /* call hook */
284 hook_property(c, "name");
287 /** Update WM_CLASS of a client.
288 * \param c The client.
289 * \param reply The reply to get property request, or NULL if none.
291 void
292 property_update_wm_class(client_t *c, xcb_get_property_reply_t *reply)
294 xcb_get_wm_class_reply_t hint;
296 if(reply)
298 if(!xcb_get_wm_class_from_reply(&hint, reply))
299 return;
301 else
303 if(!xcb_get_wm_class_reply(globalconf.connection,
304 xcb_get_wm_class_unchecked(globalconf.connection, c->win),
305 &hint, NULL))
306 return;
309 p_delete(&c->instance);
310 p_delete(&c->class);
312 c->instance = a_strdup(hint.instance_name);
313 c->class = a_strdup(hint.class_name);
314 /* only delete reply if we get it ourselves */
315 if(!reply)
316 xcb_get_wm_class_reply_wipe(&hint);
319 /** Update client icon name attribute with its new title.
320 * \param c The client.
322 void
323 property_update_wm_icon_name(client_t *c)
325 char *name;
326 ssize_t len;
328 if(!xutil_text_prop_get(globalconf.connection, c->win, _NET_WM_ICON_NAME, &name, &len))
329 if(!xutil_text_prop_get(globalconf.connection, c->win, WM_ICON_NAME, &name, &len))
330 return;
332 p_delete(&c->icon_name);
334 c->icon_name = name;
336 /* call hook */
337 hook_property(c, "icon_name");
340 static int
341 property_handle_wm_name(void *data,
342 xcb_connection_t *connection,
343 uint8_t state,
344 xcb_window_t window,
345 xcb_atom_t name,
346 xcb_get_property_reply_t *reply)
348 client_t *c = client_getbywin(window);
350 if(c)
351 property_update_wm_name(c);
353 return 0;
356 static int
357 property_handle_wm_icon_name(void *data,
358 xcb_connection_t *connection,
359 uint8_t state,
360 xcb_window_t window,
361 xcb_atom_t name,
362 xcb_get_property_reply_t *reply)
364 client_t *c = client_getbywin(window);
366 if(c)
367 property_update_wm_icon_name(c);
369 return 0;
372 static int
373 property_handle_wm_class(void *data,
374 xcb_connection_t *connection,
375 uint8_t state,
376 xcb_window_t window,
377 xcb_atom_t name,
378 xcb_get_property_reply_t *reply)
380 client_t *c = client_getbywin(window);
382 if(c)
383 property_update_wm_class(c, reply);
385 return 0;
388 static int
389 property_handle_net_wm_strut_partial(void *data,
390 xcb_connection_t *connection,
391 uint8_t state,
392 xcb_window_t window,
393 xcb_atom_t name,
394 xcb_get_property_reply_t *reply)
396 client_t *c = client_getbywin(window);
398 if(c)
399 ewmh_process_client_strut(c, reply);
401 return 0;
404 static int
405 property_handle_net_wm_icon(void *data,
406 xcb_connection_t *connection,
407 uint8_t state,
408 xcb_window_t window,
409 xcb_atom_t name,
410 xcb_get_property_reply_t *reply)
412 client_t *c = client_getbywin(window);
414 if(c)
416 luaA_object_push(globalconf.L, c);
417 luaA_object_unref_item(globalconf.L, -1, c->icon);
418 if(ewmh_window_icon_from_reply(reply))
419 c->icon = luaA_object_ref_item(globalconf.L, -2, -1);
420 else
421 c->icon = NULL;
422 /* remove client */
423 lua_pop(globalconf.L, 1);
424 /* execute hook */
425 hook_property(c, "icon");
428 return 0;
431 void
432 property_update_net_wm_pid(client_t *c,
433 xcb_get_property_reply_t *reply)
435 bool no_reply = !reply;
437 if(no_reply)
439 xcb_get_property_cookie_t prop_c =
440 xcb_get_property_unchecked(globalconf.connection, false, c->win, _NET_WM_PID, CARDINAL, 0L, 1L);
441 reply = xcb_get_property_reply(globalconf.connection, prop_c, NULL);
444 if(reply && reply->value_len)
446 uint32_t *rdata = xcb_get_property_value(reply);
447 if(rdata)
448 c->pid = *rdata;
451 if(no_reply)
452 p_delete(&reply);
455 static int
456 property_handle_net_wm_pid(void *data,
457 xcb_connection_t *connection,
458 uint8_t state,
459 xcb_window_t window,
460 xcb_atom_t name,
461 xcb_get_property_reply_t *reply)
463 client_t *c = client_getbywin(window);
465 if(c)
466 property_update_net_wm_pid(c, reply);
468 return 0;
471 /** Update the list of supported protocols for a client.
472 * \param c The client.
474 void
475 property_update_wm_protocols(client_t *c)
477 xcb_get_wm_protocols_reply_t protocols;
479 /* If this fails for any reason, we still got the old value */
480 if(xcb_get_wm_protocols_reply(globalconf.connection,
481 xcb_get_wm_protocols_unchecked(globalconf.connection,
482 c->win, WM_PROTOCOLS),
483 &protocols, NULL))
485 xcb_get_wm_protocols_reply_wipe(&c->protocols);
486 memcpy(&c->protocols, &protocols, sizeof(protocols));
490 /** The property notify event handler.
491 * \param data currently unused.
492 * \param connection currently unusued.
493 * \param state currently unused.
494 * \param window The window to obtain update protocols from.
495 * \param name currently unused.
496 * \param reply currently unused.
498 static int
499 property_handle_wm_protocols(void *data,
500 xcb_connection_t *connection,
501 uint8_t state,
502 xcb_window_t window,
503 xcb_atom_t name,
504 xcb_get_property_reply_t *reply)
506 client_t *c = client_getbywin(window);
508 if(c)
509 property_update_wm_protocols(c);
511 return 0;
514 /** The property notify event handler.
515 * \param data currently unused.
516 * \param connection The connection to the X server.
517 * \param state currently unused
518 * \param window The window to obtain update the property with.
519 * \param name The protocol atom, currently unused.
520 * \param reply (Optional) An existing reply.
522 static int
523 property_handle_xembed_info(void *data __attribute__ ((unused)),
524 xcb_connection_t *connection,
525 uint8_t state,
526 xcb_window_t window,
527 xcb_atom_t name,
528 xcb_get_property_reply_t *reply)
530 xembed_window_t *emwin = xembed_getbywin(&globalconf.embedded, window);
532 if(emwin)
533 xembed_property_update(connection, emwin, reply);
535 return 0;
538 static int
539 property_handle_xrootpmap_id(void *data __attribute__ ((unused)),
540 xcb_connection_t *connection,
541 uint8_t state,
542 xcb_window_t window,
543 xcb_atom_t name,
544 xcb_get_property_reply_t *reply)
546 if(globalconf.xinerama_is_active)
547 foreach(w, globalconf.wiboxes)
548 (*w)->need_update = true;
549 else
551 int screen = xutil_root2screen(connection, window);
552 foreach(w, globalconf.wiboxes)
553 if(screen == screen_array_indexof(&globalconf.screens, (*w)->screen))
554 (*w)->need_update = true;
557 return 0;
560 static int
561 property_handle_net_wm_opacity(void *data __attribute__ ((unused)),
562 xcb_connection_t *connection,
563 uint8_t state,
564 xcb_window_t window,
565 xcb_atom_t name,
566 xcb_get_property_reply_t *reply)
568 wibox_t *wibox = wibox_getbywin(window);
570 if(wibox)
571 wibox->opacity = window_opacity_get_from_reply(reply);
572 else
574 client_t *c = client_getbywin(window);
575 if(c)
576 c->opacity = window_opacity_get_from_reply(reply);
579 return 0;
582 void a_xcb_set_property_handlers(void)
584 /* init */
585 xcb_property_handlers_init(&globalconf.prophs, &globalconf.evenths);
587 /* Xembed stuff */
588 xcb_property_set_handler(&globalconf.prophs, _XEMBED_INFO, UINT_MAX,
589 property_handle_xembed_info, NULL);
591 /* ICCCM stuff */
592 xcb_property_set_handler(&globalconf.prophs, WM_TRANSIENT_FOR, UINT_MAX,
593 property_handle_wm_transient_for, NULL);
594 xcb_property_set_handler(&globalconf.prophs, WM_CLIENT_LEADER, UINT_MAX,
595 property_handle_wm_client_leader, NULL);
596 xcb_property_set_handler(&globalconf.prophs, WM_NORMAL_HINTS, UINT_MAX,
597 property_handle_wm_normal_hints, NULL);
598 xcb_property_set_handler(&globalconf.prophs, WM_HINTS, UINT_MAX,
599 property_handle_wm_hints, NULL);
600 xcb_property_set_handler(&globalconf.prophs, WM_NAME, UINT_MAX,
601 property_handle_wm_name, NULL);
602 xcb_property_set_handler(&globalconf.prophs, WM_ICON_NAME, UINT_MAX,
603 property_handle_wm_icon_name, NULL);
604 xcb_property_set_handler(&globalconf.prophs, WM_CLASS, UINT_MAX,
605 property_handle_wm_class, NULL);
606 xcb_property_set_handler(&globalconf.prophs, WM_PROTOCOLS, UINT_MAX,
607 property_handle_wm_protocols, NULL);
608 xcb_property_set_handler(&globalconf.prophs, WM_CLIENT_MACHINE, UINT_MAX,
609 property_handle_wm_client_machine, NULL);
610 xcb_property_set_handler(&globalconf.prophs, WM_WINDOW_ROLE, UINT_MAX,
611 property_handle_wm_window_role, NULL);
613 /* EWMH stuff */
614 xcb_property_set_handler(&globalconf.prophs, _NET_WM_NAME, UINT_MAX,
615 property_handle_wm_name, NULL);
616 xcb_property_set_handler(&globalconf.prophs, _NET_WM_ICON_NAME, UINT_MAX,
617 property_handle_wm_icon_name, NULL);
618 xcb_property_set_handler(&globalconf.prophs, _NET_WM_STRUT_PARTIAL, UINT_MAX,
619 property_handle_net_wm_strut_partial, NULL);
620 xcb_property_set_handler(&globalconf.prophs, _NET_WM_ICON, UINT_MAX,
621 property_handle_net_wm_icon, NULL);
622 xcb_property_set_handler(&globalconf.prophs, _NET_WM_PID, UINT_MAX,
623 property_handle_net_wm_pid, NULL);
624 xcb_property_set_handler(&globalconf.prophs, _NET_WM_WINDOW_OPACITY, 1,
625 property_handle_net_wm_opacity, NULL);
627 /* background change */
628 xcb_property_set_handler(&globalconf.prophs, _XROOTPMAP_ID, 1,
629 property_handle_xrootpmap_id, NULL);
632 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80