2 * ewmh.c - EWMH support functions
4 * Copyright © 2007-2008 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 <X11/Xatom.h>
32 extern AwesomeConf globalconf
;
34 static Atom net_supported
;
35 static Atom net_client_list
;
36 static Atom net_number_of_desktops
;
37 static Atom net_current_desktop
;
38 static Atom net_desktop_names
;
39 static Atom net_active_window
;
41 static Atom net_close_window
;
43 static Atom net_wm_name
;
44 static Atom net_wm_icon_name
;
45 static Atom net_wm_window_type
;
46 static Atom net_wm_window_type_normal
;
47 static Atom net_wm_window_type_dock
;
48 static Atom net_wm_window_type_splash
;
49 static Atom net_wm_icon
;
50 static Atom net_wm_state
;
51 static Atom net_wm_state_sticky
;
52 static Atom net_wm_state_skip_taskbar
;
53 static Atom net_wm_state_fullscreen
;
55 static Atom utf8_string
;
63 static AtomItem AtomNames
[] =
65 { "_NET_SUPPORTED", &net_supported
},
66 { "_NET_CLIENT_LIST", &net_client_list
},
67 { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops
},
68 { "_NET_CURRENT_DESKTOP", &net_current_desktop
},
69 { "_NET_DESKTOP_NAMES", &net_desktop_names
},
70 { "_NET_ACTIVE_WINDOW", &net_active_window
},
72 { "_NET_CLOSE_WINDOW", &net_close_window
},
74 { "_NET_WM_NAME", &net_wm_name
},
75 { "_NET_WM_ICON_NAME", &net_wm_icon_name
},
76 { "_NET_WM_WINDOW_TYPE", &net_wm_window_type
},
77 { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal
},
78 { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock
},
79 { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash
},
80 { "_NET_WM_ICON", &net_wm_icon
},
81 { "_NET_WM_STATE", &net_wm_state
},
82 { "_NET_WM_STATE_STICKY", &net_wm_state_sticky
},
83 { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar
},
84 { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen
},
86 { "UTF8_STRING", &utf8_string
},
89 #define ATOM_NUMBER (sizeof(AtomNames)/sizeof(AtomItem))
91 #define _NET_WM_STATE_REMOVE 0
92 #define _NET_WM_STATE_ADD 1
93 #define _NET_WM_STATE_TOGGLE 2
99 char *names
[ATOM_NUMBER
];
100 Atom atoms
[ATOM_NUMBER
];
102 for(i
= 0; i
< ATOM_NUMBER
; i
++)
103 names
[i
] = (char *) AtomNames
[i
].name
;
104 XInternAtoms(globalconf
.display
, names
, ATOM_NUMBER
, False
, atoms
);
105 for(i
= 0; i
< ATOM_NUMBER
; i
++)
106 *AtomNames
[i
].atom
= atoms
[i
];
110 ewmh_set_supported_hints(int phys_screen
)
112 Atom atom
[ATOM_NUMBER
];
115 atom
[i
++] = net_supported
;
116 atom
[i
++] = net_client_list
;
117 atom
[i
++] = net_number_of_desktops
;
118 atom
[i
++] = net_current_desktop
;
119 atom
[i
++] = net_desktop_names
;
120 atom
[i
++] = net_active_window
;
122 atom
[i
++] = net_close_window
;
124 atom
[i
++] = net_wm_name
;
125 atom
[i
++] = net_wm_icon_name
;
126 atom
[i
++] = net_wm_window_type
;
127 atom
[i
++] = net_wm_window_type_normal
;
128 atom
[i
++] = net_wm_window_type_dock
;
129 atom
[i
++] = net_wm_window_type_splash
;
130 atom
[i
++] = net_wm_icon
;
131 atom
[i
++] = net_wm_state
;
132 atom
[i
++] = net_wm_state_sticky
;
133 atom
[i
++] = net_wm_state_skip_taskbar
;
134 atom
[i
++] = net_wm_state_fullscreen
;
136 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
137 net_supported
, XA_ATOM
, 32,
138 PropModeReplace
, (unsigned char *) atom
, i
);
142 ewmh_update_net_client_list(int phys_screen
)
148 for(c
= globalconf
.clients
; c
; c
= c
->next
)
149 if(get_phys_screen(c
->screen
) == phys_screen
)
152 wins
= p_new(Window
, n
+ 1);
154 for(n
= 0, c
= globalconf
.clients
; c
; c
= c
->next
, n
++)
155 if(get_phys_screen(c
->screen
) == phys_screen
)
158 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
159 net_client_list
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) wins
, n
);
162 XFlush(globalconf
.display
);
166 ewmh_update_net_numbers_of_desktop(int phys_screen
)
171 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
174 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
175 net_number_of_desktops
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
179 ewmh_update_net_current_desktop(int phys_screen
)
182 Tag
*tag
, **curtags
= get_current_tags(phys_screen
);
184 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
!= curtags
[0]; tag
= tag
->next
)
187 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
188 net_current_desktop
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &count
, 1);
194 ewmh_update_net_desktop_names(int phys_screen
)
196 char buf
[1024], *pos
;
197 ssize_t len
, curr_size
;
202 for(tag
= globalconf
.screens
[phys_screen
].tags
; tag
; tag
= tag
->next
)
204 curr_size
= a_strlen(tag
->name
);
205 a_strcpy(pos
, sizeof(buf
), tag
->name
);
206 pos
+= curr_size
+ 1;
207 len
+= curr_size
+ 1;
210 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
211 net_desktop_names
, utf8_string
, 8, PropModeReplace
, (unsigned char *) buf
, len
);
215 ewmh_update_net_active_window(int phys_screen
)
218 Client
*sel
= focus_get_current_client(phys_screen
);
220 win
= sel
? sel
->win
: None
;
222 XChangeProperty(globalconf
.display
, RootWindow(globalconf
.display
, phys_screen
),
223 net_active_window
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char *) &win
, 1);
227 ewmh_process_state_atom(Client
*c
, Atom state
, int set
)
229 if(state
== net_wm_state_sticky
)
232 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
235 else if(state
== net_wm_state_skip_taskbar
)
237 if(set
== _NET_WM_STATE_REMOVE
)
239 else if(set
== _NET_WM_STATE_ADD
)
242 else if(state
== net_wm_state_fullscreen
)
244 Area area
= get_screen_area(c
->screen
, NULL
, NULL
);
245 /* reset max attribute */
246 if(set
== _NET_WM_STATE_REMOVE
)
248 else if(set
== _NET_WM_STATE_ADD
)
250 client_maximize(c
, area
.x
, area
.y
, area
.width
, area
.height
, True
);
255 ewmh_process_window_type_atom(Client
*c
, Atom state
)
257 if(state
== net_wm_window_type_normal
)
261 else if(state
== net_wm_window_type_dock
262 || state
== net_wm_window_type_splash
)
267 c
->isfloating
= True
;
271 ewmh_process_client_message(XClientMessageEvent
*ev
)
276 if(ev
->message_type
== net_current_desktop
)
277 for(screen
= 0; screen
< ScreenCount(globalconf
.display
); screen
++)
278 if(ev
->window
== RootWindow(globalconf
.display
, screen
))
279 tag_view(screen
, ev
->data
.l
[0]);
281 if(ev
->message_type
== net_close_window
)
283 if((c
= get_client_bywin(globalconf
.clients
, ev
->window
)))
286 else if(ev
->message_type
== net_wm_state
)
288 if((c
= get_client_bywin(globalconf
.clients
, ev
->window
)))
290 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[1], ev
->data
.l
[0]);
292 ewmh_process_state_atom(c
, (Atom
) ev
->data
.l
[2], ev
->data
.l
[0]);
298 ewmh_check_client_hints(Client
*c
)
302 unsigned char *data
= NULL
;
303 unsigned long i
, n
, extra
;
305 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_state
, 0L, LONG_MAX
, False
,
306 XA_ATOM
, &real
, &format
, &n
, &extra
,
307 (unsigned char **) &data
) == Success
&& data
)
309 state
= (Atom
*) data
;
310 for(i
= 0; i
< n
; i
++)
311 ewmh_process_state_atom(c
, state
[i
], _NET_WM_STATE_ADD
);
316 if(XGetWindowProperty(globalconf
.display
, c
->win
, net_wm_window_type
, 0L, LONG_MAX
, False
,
317 XA_ATOM
, &real
, &format
, &n
, &extra
,
318 (unsigned char **) &data
) == Success
&& data
)
320 state
= (Atom
*) data
;
321 for(i
= 0; i
< n
; i
++)
322 ewmh_process_window_type_atom(c
, state
[i
]);
329 ewmh_get_window_icon(Window w
)
334 unsigned long items
, rest
, *data
, pixel
;
335 unsigned char *imgdata
, *wdata
;
337 if(XGetWindowProperty(globalconf
.display
, w
,
338 net_wm_icon
, 0L, LONG_MAX
, False
, XA_CARDINAL
, &type
, &format
,
339 &items
, &rest
, &wdata
) != Success
343 if(type
!= XA_CARDINAL
|| format
!= 32 || items
< 2)
349 icon
= p_new(NetWMIcon
, 1);
351 data
= (unsigned long *) wdata
;
353 icon
->width
= data
[0];
354 icon
->height
= data
[1];
355 size
= icon
->width
* icon
->height
;
364 icon
->image
= p_new(unsigned char, size
* 4);
365 for(imgdata
= icon
->image
, i
= 2; i
< size
+ 2; i
++, imgdata
+= 4)
368 imgdata
[3] = (pixel
>> 24) & 0xff; /* A */
369 imgdata
[0] = (pixel
>> 16) & 0xff; /* R */
370 imgdata
[1] = (pixel
>> 8) & 0xff; /* G */
371 imgdata
[2] = pixel
& 0xff; /* B */
379 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80