1 | /* Gnome panel: status applet |
---|
2 | * (C) 1999-2000 the Free Software Foundation |
---|
3 | * |
---|
4 | * Authors: George Lebl |
---|
5 | */ |
---|
6 | |
---|
7 | #include <config.h> |
---|
8 | #include <string.h> |
---|
9 | #include <signal.h> |
---|
10 | #include <gnome.h> |
---|
11 | #include <gdk/gdkx.h> |
---|
12 | #include <X11/Xlib.h> |
---|
13 | #include <X11/Xatom.h> |
---|
14 | |
---|
15 | #include "panel-include.h" |
---|
16 | #include "gnome-panel.h" |
---|
17 | |
---|
18 | #include "xstuff.h" |
---|
19 | |
---|
20 | static StatusApplet *the_status = NULL; /*"there can only be one" status |
---|
21 | applet*/ |
---|
22 | static GtkWidget *offscreen = NULL; /*offscreen window for putting status |
---|
23 | spots if there is no status applet*/ |
---|
24 | static GtkWidget *fixed = NULL; /*the fixed container in which the docklets reside*/ |
---|
25 | static GSList *spots = NULL; |
---|
26 | static int nspots = 0; |
---|
27 | |
---|
28 | gboolean status_inhibit = FALSE; /*inhibit adding and updating for the purpose |
---|
29 | of quitting*/ |
---|
30 | |
---|
31 | extern GSList *applets; |
---|
32 | extern GSList *applets_last; |
---|
33 | extern int applet_count; |
---|
34 | |
---|
35 | extern PortableServer_POA thepoa; |
---|
36 | |
---|
37 | #define DOCKLET_SPOT 22 |
---|
38 | |
---|
39 | #define MINIMUM_WIDTH 10 |
---|
40 | |
---|
41 | /*this will show debug output and put the offscreen window on 10 10 to |
---|
42 | view it*/ |
---|
43 | /*#define DEBUG_STATUS 1*/ |
---|
44 | |
---|
45 | #ifdef DEBUG_STATUS |
---|
46 | #define DPUTS(x) puts(x) |
---|
47 | #define DPRINTD(d) printf("%s: %d\n",#d,d) |
---|
48 | #else |
---|
49 | #define DPUTS(x) |
---|
50 | #define DPRINTD(d) |
---|
51 | #endif |
---|
52 | |
---|
53 | StatusSpot * |
---|
54 | status_applet_get_ss(guint32 winid) |
---|
55 | { |
---|
56 | GSList *li; |
---|
57 | for(li = spots; li; li = li->next) { |
---|
58 | StatusSpot *ss = li->data; |
---|
59 | GtkSocket *s = GTK_SOCKET(ss->socket); |
---|
60 | if(s->plug_window && |
---|
61 | GDK_WINDOW_XWINDOW(s->plug_window) == winid) |
---|
62 | return ss; |
---|
63 | } |
---|
64 | return NULL; |
---|
65 | } |
---|
66 | |
---|
67 | static void |
---|
68 | ensure_fixed_and_offscreen(void) |
---|
69 | { |
---|
70 | if(!offscreen) { |
---|
71 | /* this is not supposed to happen so give a warning */ |
---|
72 | g_warning("offscreen not created yet, we must be on crack"); |
---|
73 | status_applet_create_offscreen(); |
---|
74 | } |
---|
75 | if(!fixed) { |
---|
76 | /* this is even weirder */ |
---|
77 | g_warning("fixed not created yet, we must really be on crack"); |
---|
78 | status_applet_create_offscreen(); |
---|
79 | fixed = gtk_fixed_new(); |
---|
80 | gtk_container_add(GTK_CONTAINER(offscreen), fixed); |
---|
81 | gtk_widget_show_now(fixed); |
---|
82 | } |
---|
83 | } |
---|
84 | |
---|
85 | void |
---|
86 | status_applet_update(StatusApplet *s) |
---|
87 | { |
---|
88 | GSList *li; |
---|
89 | int w,h; |
---|
90 | int sz; |
---|
91 | int rows; |
---|
92 | int i,j; |
---|
93 | |
---|
94 | if(status_inhibit) |
---|
95 | return; |
---|
96 | |
---|
97 | DPUTS("STATUS_APPLET_UPDATE"); |
---|
98 | DPRINTD(nspots); |
---|
99 | |
---|
100 | if(s->orient == PANEL_HORIZONTAL) |
---|
101 | GTK_HANDLE_BOX(s->handle)->handle_position = GTK_POS_LEFT; |
---|
102 | else |
---|
103 | GTK_HANDLE_BOX(s->handle)->handle_position = GTK_POS_TOP; |
---|
104 | |
---|
105 | sz = s->size; |
---|
106 | |
---|
107 | rows = s->size / DOCKLET_SPOT; |
---|
108 | |
---|
109 | if (rows <= 0) |
---|
110 | rows = 1; |
---|
111 | |
---|
112 | if(nspots%rows == 0) |
---|
113 | w = DOCKLET_SPOT*(nspots/rows); |
---|
114 | else |
---|
115 | w = DOCKLET_SPOT*((nspots/rows)+1); |
---|
116 | |
---|
117 | /*make minimum size*/ |
---|
118 | if(w < MINIMUM_WIDTH) w = MINIMUM_WIDTH; |
---|
119 | |
---|
120 | h = DOCKLET_SPOT*rows; |
---|
121 | |
---|
122 | /*if we are vertical just switch stuff around*/ |
---|
123 | if(s->orient == PANEL_VERTICAL) { |
---|
124 | int t = w; |
---|
125 | w = h; |
---|
126 | h = t; |
---|
127 | } |
---|
128 | |
---|
129 | gtk_widget_set_usize(fixed,w,h); |
---|
130 | |
---|
131 | DPRINTD(w); |
---|
132 | DPRINTD(h); |
---|
133 | |
---|
134 | i = j = 0; |
---|
135 | for(li = spots; li; li = li->next) { |
---|
136 | StatusSpot *ss = li->data; |
---|
137 | gtk_fixed_move(GTK_FIXED(fixed),ss->socket,i,j); |
---|
138 | i+=DOCKLET_SPOT; |
---|
139 | if(i>=w) { |
---|
140 | i = 0; |
---|
141 | j+=DOCKLET_SPOT; |
---|
142 | } |
---|
143 | } |
---|
144 | if(s->handle && s->handle->parent) |
---|
145 | gtk_widget_queue_resize(s->handle->parent); |
---|
146 | } |
---|
147 | |
---|
148 | static void |
---|
149 | status_socket_destroyed(GtkWidget *w, StatusSpot *ss) |
---|
150 | { |
---|
151 | /*so that we don't get called recursively, we set the ->socket to |
---|
152 | null inside status_spot_remove*/ |
---|
153 | if(ss->socket) |
---|
154 | status_spot_remove(ss, FALSE); |
---|
155 | } |
---|
156 | |
---|
157 | StatusSpot * |
---|
158 | new_status_spot(void) |
---|
159 | { |
---|
160 | StatusSpot *ss; |
---|
161 | |
---|
162 | if(status_inhibit) |
---|
163 | return NULL; |
---|
164 | |
---|
165 | DPUTS("NEW_STATUS_SPOT"); |
---|
166 | |
---|
167 | ss = g_new0(StatusSpot,1); |
---|
168 | ss->wid = 0; |
---|
169 | ss->sspot = CORBA_OBJECT_NIL; |
---|
170 | |
---|
171 | spots = g_slist_prepend(spots,ss); |
---|
172 | nspots++; |
---|
173 | |
---|
174 | ss->socket = gtk_socket_new(); |
---|
175 | gtk_widget_set_usize(ss->socket,DOCKLET_SPOT,DOCKLET_SPOT); |
---|
176 | |
---|
177 | /* ensures that fixed and offscreen exist, even though they |
---|
178 | * should have been created long ago, but I guess it's better |
---|
179 | * then failing an assert and disappearing */ |
---|
180 | ensure_fixed_and_offscreen(); |
---|
181 | |
---|
182 | gtk_fixed_put(GTK_FIXED(fixed),ss->socket,0,0); |
---|
183 | if(the_status) |
---|
184 | status_applet_update(the_status); |
---|
185 | |
---|
186 | gtk_widget_show_now(ss->socket); |
---|
187 | gtk_signal_connect(GTK_OBJECT(ss->socket),"destroy", |
---|
188 | GTK_SIGNAL_FUNC(status_socket_destroyed), |
---|
189 | ss); |
---|
190 | |
---|
191 | ss->wid = GDK_WINDOW_XWINDOW(ss->socket->window); |
---|
192 | return ss; |
---|
193 | } |
---|
194 | |
---|
195 | void |
---|
196 | status_spot_remove(StatusSpot *ss, gboolean destroy_socket) |
---|
197 | { |
---|
198 | CORBA_Environment ev; |
---|
199 | PortableServer_ObjectId *id; |
---|
200 | GtkWidget *w; |
---|
201 | |
---|
202 | spots = g_slist_remove(spots,ss); |
---|
203 | nspots--; |
---|
204 | |
---|
205 | /*set socket to NULL, as to indicate that we have taken |
---|
206 | care of destruction here*/ |
---|
207 | if(destroy_socket) { |
---|
208 | w = ss->socket; |
---|
209 | ss->socket = NULL; |
---|
210 | gtk_widget_destroy(w); |
---|
211 | } |
---|
212 | |
---|
213 | DPUTS("STATUS_SPOT_REMOVE"); |
---|
214 | DPRINTD(nspots); |
---|
215 | DPRINTD(g_slist_length(spots)); |
---|
216 | |
---|
217 | if(ss->sspot != CORBA_OBJECT_NIL) { |
---|
218 | CORBA_exception_init(&ev); |
---|
219 | CORBA_Object_release(ss->sspot, &ev); |
---|
220 | id = PortableServer_POA_servant_to_id(thepoa, ss, &ev); |
---|
221 | PortableServer_POA_deactivate_object(thepoa, id, &ev); |
---|
222 | CORBA_free (id); |
---|
223 | POA_GNOME_StatusSpot__fini((PortableServer_Servant) ss, &ev); |
---|
224 | CORBA_exception_free(&ev); |
---|
225 | } |
---|
226 | |
---|
227 | g_free(ss); |
---|
228 | if(the_status) status_applet_update(the_status); |
---|
229 | } |
---|
230 | |
---|
231 | /*kill all status spots*/ |
---|
232 | void |
---|
233 | status_spot_remove_all(void) |
---|
234 | { |
---|
235 | DPUTS("STATUS_SPOT_REMOVE_ALL"); |
---|
236 | |
---|
237 | while(spots) |
---|
238 | status_spot_remove(spots->data, TRUE); |
---|
239 | |
---|
240 | DPUTS("DONE REMOVE_ALL"); |
---|
241 | } |
---|
242 | |
---|
243 | void |
---|
244 | status_applet_put_offscreen(StatusApplet *s) |
---|
245 | { |
---|
246 | DPUTS("PUT_OFFSCREEN"); |
---|
247 | |
---|
248 | /* ensures that fixed and offscreen exist, even though they |
---|
249 | * should have been created long ago, but I guess it's better |
---|
250 | * then failing an assert and disappearing */ |
---|
251 | ensure_fixed_and_offscreen(); |
---|
252 | |
---|
253 | if(fixed->parent != offscreen) { |
---|
254 | DPUTS("REPARENT"); |
---|
255 | gtk_widget_reparent(fixed, offscreen); |
---|
256 | DPUTS("REPARENT DONE"); |
---|
257 | } |
---|
258 | } |
---|
259 | |
---|
260 | void |
---|
261 | status_applet_create_offscreen(void) |
---|
262 | { |
---|
263 | DPUTS("CREATE OFFSCREEN"); |
---|
264 | offscreen = gtk_window_new(GTK_WINDOW_POPUP); |
---|
265 | #ifdef DEBUG_STATUS |
---|
266 | gtk_widget_set_uposition(offscreen,10,10); |
---|
267 | #else |
---|
268 | gtk_widget_set_uposition(offscreen, gdk_screen_width()+10, |
---|
269 | gdk_screen_height()+10); |
---|
270 | #endif |
---|
271 | if(!fixed) { |
---|
272 | fixed = gtk_fixed_new(); |
---|
273 | gtk_widget_show(fixed); |
---|
274 | |
---|
275 | gtk_container_add(GTK_CONTAINER(offscreen), fixed); |
---|
276 | } |
---|
277 | |
---|
278 | gtk_widget_show_now(offscreen); |
---|
279 | |
---|
280 | /* if this fails we are seriously in trouble */ |
---|
281 | g_assert(offscreen->window); |
---|
282 | |
---|
283 | xstuff_setup_kde_dock_thingie(offscreen->window); |
---|
284 | } |
---|
285 | |
---|
286 | static int |
---|
287 | ignore_1st_click(GtkWidget *widget, GdkEvent *event) |
---|
288 | { |
---|
289 | GdkEventButton *buttonevent = (GdkEventButton *)event; |
---|
290 | |
---|
291 | if((event->type == GDK_BUTTON_PRESS && |
---|
292 | buttonevent->button == 1) || |
---|
293 | (event->type == GDK_BUTTON_RELEASE && |
---|
294 | buttonevent->button == 1)) { |
---|
295 | buttonevent->button = 2; |
---|
296 | } |
---|
297 | |
---|
298 | return FALSE; |
---|
299 | } |
---|
300 | |
---|
301 | static void |
---|
302 | free_status (gpointer data) |
---|
303 | { |
---|
304 | StatusApplet *s = data; |
---|
305 | g_free(s); |
---|
306 | |
---|
307 | the_status = NULL; |
---|
308 | } |
---|
309 | |
---|
310 | static void |
---|
311 | reparent_fixed(GtkWidget *frame) |
---|
312 | { |
---|
313 | if(fixed->parent != frame) { |
---|
314 | DPUTS("REPARENT"); |
---|
315 | gtk_widget_reparent(fixed, frame); |
---|
316 | DPUTS("REPARENT DONE"); |
---|
317 | } |
---|
318 | } |
---|
319 | |
---|
320 | gboolean |
---|
321 | load_status_applet(PanelWidget *panel, int pos, gboolean exactpos) |
---|
322 | { |
---|
323 | GtkWidget *ebox; |
---|
324 | if(the_status) |
---|
325 | return FALSE; |
---|
326 | |
---|
327 | DPUTS("LOAD_STATUS_APPLET"); |
---|
328 | |
---|
329 | the_status = g_new0(StatusApplet,1); |
---|
330 | the_status->orient = panel->orient; |
---|
331 | the_status->size = panel->sz; |
---|
332 | the_status->handle = gtk_handle_box_new(); |
---|
333 | gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(the_status->handle), |
---|
334 | GTK_SHADOW_IN); |
---|
335 | gtk_container_set_border_width(GTK_CONTAINER(the_status->handle), |
---|
336 | 1); |
---|
337 | gtk_signal_connect(GTK_OBJECT(the_status->handle), "event", |
---|
338 | GTK_SIGNAL_FUNC(ignore_1st_click), NULL); |
---|
339 | |
---|
340 | if(!fixed) { |
---|
341 | DPUTS("NO FIXED"); |
---|
342 | fixed = gtk_fixed_new(); |
---|
343 | gtk_container_set_border_width(GTK_CONTAINER(fixed), |
---|
344 | 0); |
---|
345 | gtk_widget_show(fixed); |
---|
346 | |
---|
347 | gtk_container_add(GTK_CONTAINER(the_status->handle), fixed); |
---|
348 | } else { |
---|
349 | gtk_signal_connect_after(GTK_OBJECT(the_status->handle), "realize", |
---|
350 | GTK_SIGNAL_FUNC(reparent_fixed), |
---|
351 | NULL); |
---|
352 | } |
---|
353 | |
---|
354 | status_applet_update(the_status); |
---|
355 | |
---|
356 | ebox = gtk_event_box_new(); |
---|
357 | gtk_container_set_border_width(GTK_CONTAINER(ebox), |
---|
358 | 0); |
---|
359 | gtk_widget_show(ebox); |
---|
360 | gtk_container_add(GTK_CONTAINER(ebox),the_status->handle); |
---|
361 | |
---|
362 | if(!register_toy(ebox, the_status, free_status, |
---|
363 | panel, pos, exactpos, APPLET_STATUS)) |
---|
364 | return TRUE; |
---|
365 | the_status->info = applets_last->data; |
---|
366 | applet_add_callback(applets_last->data, "help", |
---|
367 | GNOME_STOCK_PIXMAP_HELP, |
---|
368 | _("Help")); |
---|
369 | return TRUE; |
---|
370 | } |
---|