1 /**************************************************************************
4 * Copyright (C) 2009 thierry lorthiois (lorthiois@bbsoft.fr)
5 * based on 'docker-1.5' from Ben Jansens.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **************************************************************************/
21 #include <X11/Xutil.h>
22 #include <X11/Xatom.h>
29 #include "systraybar.h"
35 /* defined in the systray spec */
36 #define SYSTEM_TRAY_REQUEST_DOCK 0
37 #define SYSTEM_TRAY_BEGIN_MESSAGE 1
38 #define SYSTEM_TRAY_CANCEL_MESSAGE 2
41 Window net_sel_win
= None
, hint_win
= None
;
43 // freedesktop specification doesn't allow multi systray
50 Panel
*panel
= &panel1
[0];
52 if (systray
.area
.on_screen
)
53 systray
.area
.on_screen
= init_net();
55 if (!systray
.area
.on_screen
)
58 systray
.area
.parent
= panel
;
59 systray
.area
.panel
= panel
;
60 systray
.area
._draw_foreground
= draw_systray
;
61 systray
.area
._resize
= resize_systray
;
65 // draw only one systray (even with multi panel)
66 systray
.area
.posy
= panel
->area
.pix
.border
.width
+ panel
->area
.paddingy
;
67 systray
.area
.height
= panel
->area
.height
- (2 * systray
.area
.posy
);
68 systray
.area
.width
= 0;
69 systray
.area
.redraw
= 1;
71 systray
.area
.posx
= panel
->area
.width
- panel
->area
.paddingxlr
- panel
->area
.pix
.border
.width
- systray
.area
.width
;
72 if (panel
->clock
.area
.on_screen
)
73 systray
.area
.posx
-= (panel
->clock
.area
.width
+ panel
->area
.paddingx
);
75 if (panel
->battery
.area
.on_screen
)
76 systray
.area
.posx
-= (panel
->battery
.area
.width
+ panel
->area
.paddingx
);
81 void cleanup_systray()
83 if (systray
.list_icons
) {
86 for (it
= systray
.list_icons
; it
; it
= it
->next
)
87 remove_icon((TrayWindow
*)it
->data
);
89 g_slist_free(systray
.list_icons
);
90 systray
.list_icons
= 0;
93 free_area(&systray
.area
);
99 void draw_systray(void *obj
, cairo_t
*c
, int active
)
101 // tint2 don't draw systray icons. just the background.
106 void resize_systray(void *obj
)
108 Systraybar
*sysbar
= obj
;
109 Panel
*panel
= sysbar
->area
.panel
;
112 int count
, posx
, posy
;
115 icon_size
= sysbar
->area
.height
- (2 * sysbar
->area
.pix
.border
.width
) - (2 * sysbar
->area
.paddingy
);
116 count
= g_slist_length(systray
.list_icons
);
118 if (!count
) systray
.area
.width
= 0;
119 else systray
.area
.width
= (2 * systray
.area
.pix
.border
.width
) + (2 * systray
.area
.paddingxlr
) + (icon_size
* count
) + ((count
-1) * systray
.area
.paddingx
);
121 systray
.area
.posx
= panel
->area
.width
- panel
->area
.pix
.border
.width
- panel
->area
.paddingxlr
- systray
.area
.width
;
122 if (panel
->clock
.area
.on_screen
)
123 systray
.area
.posx
-= (panel
->clock
.area
.width
+ panel
->area
.paddingx
);
124 #ifdef ENABLE_BATTERY
125 if (panel
->battery
.area
.on_screen
)
126 systray
.area
.posx
-= (panel
->battery
.area
.width
+ panel
->area
.paddingx
);
129 posy
= panel
->area
.pix
.border
.width
+ panel
->area
.paddingy
+ systray
.area
.pix
.border
.width
+ systray
.area
.paddingy
;
130 posx
= systray
.area
.posx
+ systray
.area
.pix
.border
.width
+ systray
.area
.paddingxlr
;
131 for (l
= systray
.list_icons
; l
; l
= l
->next
) {
132 traywin
= (TrayWindow
*)l
->data
;
136 traywin
->width
= icon_size
;
137 traywin
->height
= icon_size
;
138 posx
+= (icon_size
+ systray
.area
.paddingx
);
140 // position and size the icon window
141 XMoveResizeWindow(server
.dsp
, traywin
->id
, traywin
->x
, traywin
->y
, icon_size
, icon_size
);
143 //printf("resize_systray %d %d\n", systray.area.posx, systray.area.width);
147 void create_hint_win()
150 XClassHint classhints;
151 Panel *panel = systray.area.panel;
153 hint_win = XCreateSimpleWindow(server.dsp, server.root_win, 0, 0, 1, 1, 0, 0, 0);
155 hints.flags = StateHint | WindowGroupHint | IconWindowHint;
156 hints.initial_state = WithdrawnState;
157 hints.window_group = hint_win;
158 hints.icon_window = panel->main_win;
160 classhints.res_name = "docker";
161 classhints.res_class = "Docker";
163 XSetWMProperties(server.dsp, hint_win, NULL, NULL, NULL, 0,
164 NULL, &hints, &classhints);
166 XMapWindow(server.dsp, hint_win);
172 if (XGetSelectionOwner(server
.dsp
, server
.atom
._NET_SYSTEM_TRAY_SCREEN
) != None
) {
173 fprintf(stderr
, "tint2 : another systray is running\n");
179 // init systray protocol
180 net_sel_win
= XCreateSimpleWindow(server
.dsp
, server
.root_win
, -1, -1, 1, 1, 0, 0, 0);
182 // v0.2 trayer specification. tint2 always orizontal.
184 XChangeProperty(server
.dsp
, net_sel_win
, server
.atom
._NET_SYSTEM_TRAY_ORIENTATION
, XA_CARDINAL
, 32, PropModeReplace
, (unsigned char *) &orient
, 1);
186 XSetSelectionOwner(server
.dsp
, server
.atom
._NET_SYSTEM_TRAY_SCREEN
, net_sel_win
, CurrentTime
);
187 if (XGetSelectionOwner(server
.dsp
, server
.atom
._NET_SYSTEM_TRAY_SCREEN
) != net_sel_win
) {
188 fprintf(stderr
, "tint2 : can't get systray manager\n");
192 XClientMessageEvent ev
;
193 ev
.type
= ClientMessage
;
194 ev
.window
= server
.root_win
;
195 ev
.message_type
= server
.atom
.MANAGER
;
197 ev
.data
.l
[0] = CurrentTime
;
198 ev
.data
.l
[1] = server
.atom
._NET_SYSTEM_TRAY_SCREEN
;
199 ev
.data
.l
[2] = net_sel_win
;
202 XSendEvent(server
.dsp
, server
.root_win
, False
, StructureNotifyMask
, (XEvent
*)&ev
);
209 if (net_sel_win
!= None
) {
210 XDestroyWindow(server
.dsp
, net_sel_win
);
217 int window_error_handler(Display
*d
, XErrorEvent
*e
)
221 if (e
->error_code
!= BadWindow
) {
222 printf("error_handler %d\n", e
->error_code
);
228 // The traywin must have its id and type set.
229 gboolean
add_icon(Window id
)
233 Panel
*panel
= systray
.area
.panel
;
236 old
= XSetErrorHandler(window_error_handler
);
237 XReparentWindow(server
.dsp
, id
, panel
->main_win
, 0, 0);
238 XSync(server
.dsp
, False
);
239 XSetErrorHandler(old
);
241 if (error
!= FALSE
) {
242 fprintf(stderr
, "tint2 : not icon_swallow\n");
246 traywin
= g_new0(TrayWindow
, 1);
249 systray
.list_icons
= g_slist_prepend(systray
.list_icons
, traywin
);
250 //printf("ajout d'un icone %d (%lx)\n", g_slist_length(systray.list_icons), id);
251 systray
.area
.resize
= 1;
252 systray
.area
.redraw
= 1;
254 // watch for the icon trying to resize itself!
255 XSelectInput(server
.dsp
, traywin
->id
, StructureNotifyMask
);
258 XMapRaised(server
.dsp
, traywin
->id
);
260 // changed in systray force resize on panel
261 panel
->area
.resize
= 1;
267 void remove_icon(TrayWindow
*traywin
)
271 XSelectInput(server
.dsp
, traywin
->id
, NoEventMask
);
275 old
= XSetErrorHandler(window_error_handler
);
276 XReparentWindow(server
.dsp
, traywin
->id
, server
.root_win
, 0, 0);
277 XSync(server
.dsp
, False
);
278 XSetErrorHandler(old
);
280 // remove from our list
281 systray
.list_icons
= g_slist_remove(systray
.list_icons
, traywin
);
283 //printf("suppression d'un icone %d\n", g_slist_length(systray.list_icons));
284 systray
.area
.resize
= 1;
285 systray
.area
.redraw
= 1;
287 // changed in systray force resize on panel
288 Panel
*panel
= systray
.area
.panel
;
289 panel
->area
.resize
= 1;
295 void net_message(XClientMessageEvent
*e
)
297 unsigned long opcode
;
300 opcode
= e
->data
.l
[1];
302 case SYSTEM_TRAY_REQUEST_DOCK
:
304 if (id
) add_icon(id
);
307 case SYSTEM_TRAY_BEGIN_MESSAGE
:
308 case SYSTEM_TRAY_CANCEL_MESSAGE
:
309 // we don't show baloons messages.
313 if (opcode
== server
.atom
._NET_SYSTEM_TRAY_MESSAGE_DATA
) {
314 printf("message from dockapp: %s\n", e
->data
.b
);
317 printf("SYSTEM_TRAY : unknown message type\n");
323 void refresh_systray_icon()
327 for (l
= systray
.list_icons
; l
; l
= l
->next
) {
328 traywin
= (TrayWindow
*)l
->data
;
329 XClearArea(server
.dsp
, traywin
->id
, 0, 0, traywin
->width
, traywin
->height
, True
);