1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <locale.h>
8 #include <string.h>
9 #include <signal.h>
10 
11 #include <gdk/gdk.h>
12 
13 #include "panel.h"
14 #include "misc.h"
15 #include "bg.h"
16 #include "main.h"
17 #include "gdk-helper.h"
18 
19 #define VERSION "1.1.8"
20 
21 static gchar version[] = VERSION;
22 int distance=0, distancefrom=DISTANCEFROM_TOP;
23 int expand=1 , padding=0;
24 
25 
26 //#define DEBUG
27 #include "dbg.h"
28 
29 
30 static panel *p;
31 static gchar *transparent_rc = "style 'transparent-style'\n"
32 "{\n"
33 "bg_pixmap[NORMAL] = \"<parent>\"\n"
34 "bg_pixmap[INSENSITIVE] = \"<parent>\"\n"
35 "bg_pixmap[PRELIGHT] = \"<parent>\"\n"
36 "bg_pixmap[SELECTED] = \"<parent>\"\n"
37 "bg_pixmap[ACTIVE] = \"<parent>\"\n"
38 "}\n"
39 "class \"GtkEventBox\" style \"transparent-style\"\n"
40 "class \"GtkSocket\" style \"transparent-style\"\n"
41 "class \"GtkBar\" style \"transparent-style\"\n"
42 "class \"GtkBox\" style \"transparent-style\"\n"
43 "\n";
44 
45 static void set_bg(GtkWidget *widget, panel *p);
46 
47 /****************************************************
48  *         panel's handlers for WM events           *
49  ****************************************************/
50 /*
51 static void
52 panel_del_wm_strut(panel *p)
53 {
54     XDeleteProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT);
55     XDeleteProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
56 }
57 */
58 
59 static void
panel_set_wm_strut(panel * p)60 panel_set_wm_strut(panel *p)
61 {
62     unsigned long data[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
63     int i = 4;
64 
65     ENTER;
66     if (!GTK_WIDGET_MAPPED (p->topgwin))
67         return;
68     switch (p->edge) {
69     case EDGE_LEFT:
70         i = 0;
71         data[i] = p->aw;
72         data[4 + i*2] = p->ay;
73         data[5 + i*2] = p->ay + p->ah - 1;
74         break;
75     case EDGE_RIGHT:
76         i = 1;
77         data[i] = p->aw;
78         data[4 + i*2] = p->ay;
79         data[5 + i*2] = p->ay + p->ah - 1;
80         break;
81     case EDGE_TOP:
82         i = 2;
83         data[i] = p->ah;
84         data[4 + i*2] = p->ax;
85         data[5 + i*2] = p->ax + p->aw - 1;
86         break;
87     case EDGE_BOTTOM:
88         i = 3;
89         data[i] = p->ah;
90         data[4 + i*2] = p->ax;
91         data[5 + i*2] = p->ax + p->aw - 1 ;
92         break;
93     default:
94         ERR("wrong edge %d. strut won't be set\n", p->edge);
95         RET();
96     }
97     DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
98 
99     XChangeProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
100                     XA_CARDINAL, 32, PropModeReplace,  (unsigned char *) data, 12);
101    /* old spec, for wms that do not support STRUT_PARTIAL */
102     XChangeProperty(gdk_helper_display(), p->topxwin, a_NET_WM_STRUT,
103                     XA_CARDINAL, 32, PropModeReplace,  (unsigned char *) data, 4);
104 
105     RET();
106 }
107 
108 static GdkFilterReturn
panel_wm_events(GdkXEvent * xevent,GdkEvent * event,panel * p)109 panel_wm_events(GdkXEvent *xevent, GdkEvent *event, panel *p)
110 {
111     Atom at;
112     Window win;
113     XEvent *ev = (XEvent *) xevent;
114 
115     ENTER;
116     DBG("win = 0x%x\n", ev->xproperty.window);
117     if ( ev->type != PropertyNotify )
118         RET(GDK_FILTER_CONTINUE);
119 
120     at = ev->xproperty.atom;
121     win = ev->xproperty.window;
122     if (win == GDK_ROOT_WINDOW()) {
123       if (at == a_XROOTPMAP_ID) {
124             bg_rootbg_changed();
125             set_bg(p->topgwin, p);
126             gtk_widget_queue_draw(p->topgwin);
127             DBG("a_XROOTPMAP_ID\n");
128       }
129     }
130     RET(GDK_FILTER_CONTINUE);
131 }
132 
133 /****************************************************
134  *         panel's handlers for GTK events          *
135  ****************************************************/
136 
137 
138 static gint
panel_delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)139 panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
140 {
141     ENTER;
142     RET(FALSE);
143 }
144 
145 static gint
panel_destroy_event(GtkWidget * widget,GdkEvent * event,gpointer data)146 panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
147 {
148     ENTER;
149     // TODO need to cleanup
150     gtk_main_quit();
151     RET(FALSE);
152 }
153 
154 
155 
156 static gint
panel_size_req(GtkWidget * widget,GtkRequisition * req,panel * p)157 panel_size_req(GtkWidget *widget, GtkRequisition *req, panel *p)
158 {
159     ENTER;
160     DBG("IN req=(%d, %d)\n", req->width, req->height);
161     if (p->widthtype == WIDTH_REQUEST)
162         p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
163     if (p->heighttype == HEIGHT_REQUEST)
164         p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
165     calculate_position(p, distance,distancefrom);
166     req->width  = p->aw;
167     req->height = p->ah;
168     DBG("OUT req=(%d, %d)\n", req->width, req->height);
169     RET( TRUE );
170 }
171 
172 static gint
panel_size_alloc(GtkWidget * widget,GtkAllocation * a,panel * p)173 panel_size_alloc(GtkWidget *widget, GtkAllocation *a, panel *p)
174 {
175     ENTER;
176     DBG("new alloc: size (%d, %d). pos (%d, %d)\n", a->width, a->height, a->x, a->y);
177     DBG("old alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
178     if (p->widthtype == WIDTH_REQUEST)
179         p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
180     if (p->heighttype == HEIGHT_REQUEST)
181         p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
182     calculate_position(p, distance,distancefrom);
183     DBG("pref alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
184     if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
185         DBG("actual coords eq to preffered. just returning\n");
186         RET(TRUE);
187     }
188 
189     gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
190     if (p->setstrut)
191         panel_set_wm_strut(p);
192     RET(TRUE);
193 }
194 
195 
196 
197 
198 /****************************************************
199  *         panel creation                           *
200  ****************************************************/
201 
202   static void
set_bg(GtkWidget * widget,panel * p)203 set_bg(GtkWidget *widget, panel *p)
204 {
205     ENTER;
206     if (p->gtopbg)
207         g_object_unref(p->gtopbg);
208     p->gtopbg = bg_new_for_win(p->topxwin);
209 
210     modify_drawable(p->gtopbg, p->topgwin->style->black_gc, p->tintcolor, p->alpha);
211 
212     gdk_window_set_back_pixmap(p->topgwin->window, p->gtopbg, FALSE);
213     gdk_window_clear(p->topgwin->window);
214     gtk_widget_queue_draw_area (p->topgwin, 0, 0, 2000, 2000);
215     RET();
216 }
217 
218 static void
panel_style_set(GtkWidget * widget,GtkStyle * s,panel * p)219 panel_style_set(GtkWidget *widget, GtkStyle *s, panel *p)
220 {
221     ENTER;
222 
223     gtk_rc_parse_string(transparent_rc);
224     if (GTK_WIDGET_REALIZED(widget))
225         set_bg(widget, p);
226     RET();
227 }
228 
229 static gboolean
panel_configure_event(GtkWidget * widget,GdkEventConfigure * event,panel * p)230 panel_configure_event(GtkWidget *widget, GdkEventConfigure *event, panel *p)
231 {
232     static gint x = 0, y = 0, width = 0, height = 0;
233 
234     ENTER;
235     if (x == event->x && y == event->y
236           && width == event->width && height == event->height)
237         RET(FALSE);
238     x = event->x;
239     y = event->y;
240     width = event->width;
241     height = event->height;
242     set_bg(widget, p);
243     RET(FALSE);
244 }
245 
246 static gboolean
panel_monitors_changed(GdkScreen * s,panel * p)247 panel_monitors_changed(GdkScreen* s, panel* p)
248 {
249     ENTER;
250     if ( p->on_primary ) {
251       p->monitor = gdk_screen_get_primary_monitor(s);
252     }
253     calculate_position(p, distance,distancefrom);
254     gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
255     if (p->setstrut)
256         panel_set_wm_strut(p);
257     RET(TRUE);
258 }
259 
260 void
panel_start_gui(panel * p)261 panel_start_gui(panel *p)
262 {
263     ENTER;
264     //gtk_rc_parse_string(transparent_rc);
265     p->topgwin      = gtk_window_new(GTK_WINDOW_TOPLEVEL);
266 
267     gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
268     gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
269     gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "trayer");
270     gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
271     gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_CENTER);
272     g_signal_connect ( G_OBJECT(p->topgwin) , "delete-event" , G_CALLBACK(panel_delete_event) , p);
273     g_signal_connect ( G_OBJECT(p->topgwin) , "destroy-event", G_CALLBACK(panel_destroy_event), p);
274     g_signal_connect ( G_OBJECT (p->topgwin), "size-request" , G_CALLBACK(panel_size_req)  , p);
275     g_signal_connect ( G_OBJECT (p->topgwin), "size-allocate", G_CALLBACK(panel_size_alloc), p);
276 
277     if (p->transparent) {
278       g_signal_connect (G_OBJECT (p->topgwin), "configure-event", G_CALLBACK(panel_configure_event), p);
279       g_signal_connect (G_OBJECT (p->topgwin), "style-set", G_CALLBACK( panel_style_set), p);
280     }
281 
282     GdkDisplay *display = gdk_display_get_default ();
283     GdkScreen *screen = gdk_display_get_default_screen(display);
284     g_signal_connect ( screen, "monitors-changed", G_CALLBACK(panel_monitors_changed), (gpointer)p );
285 
286     if (p->on_primary) {
287         p->monitor = gdk_screen_get_primary_monitor(screen);
288 
289     }
290 
291     gtk_widget_realize(p->topgwin);
292     gdk_window_set_decorations(p->topgwin->window, 0);
293     gtk_widget_set_app_paintable(p->topgwin, TRUE);
294 
295     p->lbox = p->my_box_new(FALSE, 0);
296     gtk_container_set_border_width(GTK_CONTAINER(p->lbox), 0);
297     gtk_container_add(GTK_CONTAINER(p->topgwin), p->lbox);
298     gtk_widget_show(p->lbox);
299 
300     if (p->allign == ALLIGN_RIGHT) {
301         GtkWidget * expander = p->my_box_new(FALSE, 0);
302         gtk_box_pack_start(GTK_BOX(p->lbox), expander, TRUE, TRUE, 0);
303         gtk_widget_show(expander);
304     }
305 
306     p->box = p->my_box_new(FALSE, 1);
307     gtk_container_set_border_width(GTK_CONTAINER(p->box), 1);
308     gtk_box_pack_start(GTK_BOX(p->lbox), p->box, FALSE, TRUE, padding);
309     gtk_widget_show(p->box);
310 
311     // get properties on topgwin
312     p->topGdkWindow = gtk_widget_get_window(p->topgwin);
313     p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
314 
315     bg_init(gdk_helper_display());
316 
317     /* make our window unfocusable */
318     gdk_window_set_accept_focus(p->topGdkWindow,False);
319 
320     if (p->setdocktype) {
321         gdk_window_set_type_hint(p->topGdkWindow,GDK_WINDOW_TYPE_HINT_DOCK);
322     }
323 
324     Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
325 
326     /************************/
327     /* Window Mapping Point */
328     gtk_widget_show_all(p->topgwin);
329     Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
330 
331     gdk_window_stick                 ( p->topGdkWindow);
332     gdk_window_set_skip_pager_hint   ( p->topGdkWindow, True );
333     gdk_window_set_skip_taskbar_hint ( p->topGdkWindow, True );
334 
335     XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), PropertyChangeMask);
336     XSelectInput (gdk_helper_display(), p->topxwin, PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
337     gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
338 
339     calculate_position(p, distance,distancefrom);
340     gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
341     if (p->setstrut)
342         panel_set_wm_strut(p);
343     if (p->lower)
344         XLowerWindow(gdk_helper_display(), p->topxwin);
345 
346     RET();
347 }
348 
349 static int
panel_parse_global(panel * p)350 panel_parse_global(panel *p)
351 {
352     ENTER;
353     p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
354         ? ORIENT_HORIZ : ORIENT_VERT;
355     if (p->orientation == ORIENT_HORIZ) {
356         p->my_box_new = gtk_hbox_new;
357     } else {
358         p->my_box_new = gtk_vbox_new;
359     }
360     if (p->width < 0)
361         p->width = 100;
362     if (p->widthtype == WIDTH_PERCENT && p->width > 100)
363         p->width = 100;
364     p->heighttype = HEIGHT_PIXEL;
365     if (p->heighttype == HEIGHT_PIXEL) {
366         if (p->height < PANEL_HEIGHT_MIN) {
367             ERR( "height is bound by %i pixels\n", PANEL_HEIGHT_MIN );
368             p->height = PANEL_HEIGHT_MIN;
369         } else if (p->height > PANEL_HEIGHT_MAX) {
370             ERR( "height is bound by %i pixels\n", PANEL_HEIGHT_MAX );
371             p->height = PANEL_HEIGHT_MAX;
372         }
373     }
374     panel_start_gui(p);
375     RET(1);
376 }
377 
378 int
panel_start(panel * p)379 panel_start(panel *p)
380 {
381     /* parse global section */
382     ENTER;
383 
384     if (!panel_parse_global(p))
385         RET(0);
386 
387     if (!tray_constructor(p))
388         RET(0);
389 
390     gtk_widget_show_all(p->topgwin);
391     RET(1);
392 }
393 
panel_stop(panel * p)394 void panel_stop(panel *p)
395 {
396     ENTER;
397 
398     tray_destructor(p);
399     XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), NoEventMask);
400     gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
401     gtk_widget_destroy(p->topgwin);
402     RET();
403 }
404 
405 void
usage()406 usage()
407 {
408     ENTER;
409     printf("trayer %s - lightweight GTK2+ systray for UNIX desktops\n", version);
410     printf("Command line options:\n");
411     printf(" -h  -- print this help and exit\n");
412     printf(" -v  -- print version and exit\n");
413     printf(" -l  -- lower the window on startup\n");
414     printf(" --edge       <left|right|top|bottom|none> (default:bottom) \n");
415     printf(" --align      <left|right|center>          (default:center)\n");
416     printf(" --margin     <number>                     (default:0)\n");
417     printf(" --widthtype  <request|pixel|percent>      (default:percent)\n");
418     printf(" --width      <number>                     (default:%i)\n",PANEL_WIDTH_DEFAULT);
419     printf(" --heighttype <request|pixel>              (default:pixel)\n");
420     printf(" --height     <number>                     (default:%i)\n",PANEL_HEIGHT_DEFAULT);
421     printf(" --SetDockType     <true|false>            (default:true)\n");
422     printf(" --SetPartialStrut <true|false>            (default:true)\n");
423     printf(" --transparent     <true|false>            (default:false)\n");
424     printf(" --alpha      <number>                     (default:127)\n");
425     printf(" --tint       <int>                        (default:0xFFFFFFFF)\n");
426     printf(" --distance   <number>                     (default:0)\n");
427     printf(" --distancefrom <left|right|top|bottom>    (default:top) \n");
428     printf(" --expand     <false|true>                 (default:true)\n");
429     printf(" --padding    <number>                     (default:0)\n");
430     printf(" --monitor    <number|primary>             (default:0)\n");
431     printf(" --iconspacing <number>                    (default:0)\n");
432 }
433 
434 void
handle_error(Display * d,XErrorEvent * ev)435 handle_error(Display * d, XErrorEvent * ev)
436 {
437     char buf[256];
438 
439     ENTER;
440     XGetErrorText(gdk_helper_display(), ev->error_code, buf, 256);
441     ERR( "trayer : X error: %s\n", buf);
442     RET();
443 }
444 
445 int
main(int argc,char * argv[],char * env[])446 main(int argc, char *argv[], char *env[])
447 {
448     int i;
449 
450     ENTER;
451     setlocale(LC_CTYPE, "");
452     gtk_init(&argc, &argv);
453     XSetLocaleModifiers("");
454     XSetErrorHandler((XErrorHandler) handle_error);
455     // resolve xatoms
456     resolve_atoms();
457 
458     p = g_new0(panel, 1);
459     memset(p, 0, sizeof(panel));
460     p->allign = ALLIGN_CENTER;
461     p->edge = EDGE_BOTTOM;
462     p->widthtype = WIDTH_PERCENT;
463     p->width = PANEL_WIDTH_DEFAULT;
464     p->heighttype = HEIGHT_PIXEL;
465     p->height = PANEL_HEIGHT_DEFAULT;
466     p->setdocktype = 1;
467     p->setstrut = 0;
468     p->transparent = 0;
469     p->icon_spacing = 0;
470     p->alpha = 127;
471     p->tintcolor = 0xFFFFFFFF;
472     p->xtopbg = None;
473     p->monitor = 0;
474     p->margin = 0;
475     p->on_primary = 0;
476 
477     for (i = 1; i < argc; i++) {
478         if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
479             usage();
480             exit(0);
481         } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
482             printf("trayer %s\n", version);
483             exit(0);
484         } else if (!strcmp(argv[i], "-l")) {
485             p->lower = 1;
486         } else if (!strcmp(argv[i], "--edge")) {
487             i++;
488             if (i == argc) {
489                 ERR( "trayer: missing edge parameter value\n");
490                 usage();
491                 exit(1);
492             } else {
493                 p->edge = str2num(edge_pair, argv[i], EDGE_NONE);
494             }
495         } else if (!strcmp(argv[i], "--align")) {
496             i++;
497             if (i == argc) {
498                 ERR( "trayer: missing align parameter value\n");
499                 usage();
500                 exit(1);
501             } else {
502                 p->allign = str2num(allign_pair, argv[i], ALLIGN_NONE);
503             }
504         } else if (!strcmp(argv[i], "--margin")) {
505             i++;
506             if (i == argc) {
507                 ERR( "trayer: missing margin parameter value\n");
508                 usage();
509                 exit(1);
510             } else {
511                 p->margin = atoi(argv[i]);
512             }
513         } else if (!strcmp(argv[i], "--widthtype")) {
514             i++;
515             if (i == argc) {
516                 ERR( "trayer: missing widthtype parameter value\n");
517                 usage();
518                 exit(1);
519             } else {
520                 p->widthtype = str2num(width_pair, argv[i], WIDTH_NONE);
521             }
522         } else if (!strcmp(argv[i], "--width")) {
523             i++;
524             if (i == argc) {
525                 ERR( "trayer: missing width parameter value\n");
526                 usage();
527                 exit(1);
528             } else {
529                 p->width = atoi(argv[i]);
530             }
531         } else if (!strcmp(argv[i], "--heighttype")) {
532             i++;
533             if (i == argc) {
534                 ERR( "trayer: missing heighttype parameter value\n");
535                 usage();
536                 exit(1);
537             } else {
538                 p->heighttype = str2num(height_pair, argv[i], HEIGHT_NONE);
539             }
540         } else if (!strcmp(argv[i], "--height")) {
541             i++;
542             if (i == argc) {
543                 ERR( "trayer: missing height parameter value\n");
544                 usage();
545                 exit(1);
546             } else {
547                 p->height = atoi(argv[i]);
548             }
549         } else if (!strcmp(argv[i], "--SetDockType")) {
550             i++;
551             if (i == argc) {
552                 ERR( "trayer: missing SetDockType parameter value\n");
553                 usage();
554                 exit(1);
555             } else {
556                 p->setdocktype = str2num(bool_pair, argv[i], 0);
557             }
558         } else if (!strcmp(argv[i], "--SetPartialStrut")) {
559             i++;
560             if (i == argc) {
561                 ERR( "trayer: missing SetPartialStrut parameter value\n");
562                 usage();
563                 exit(1);
564             } else {
565                 p->setstrut = str2num(bool_pair, argv[i], 0);
566             }
567         } else if (!strcmp(argv[i], "--transparent")) {
568             i++;
569             if (i == argc) {
570                 ERR( "trayer: missing transparent parameter value\n");
571                 usage();
572                 exit(1);
573             } else {
574                 p->transparent = str2num(bool_pair, argv[i], 1);
575             }
576         } else if (!strcmp(argv[i], "--alpha")) {
577             i++;
578             if (i == argc) {
579                 ERR( "trayer: missing alpha parameter value\n");
580                 usage();
581                 exit(1);
582             } else {
583                 p->alpha = atoi(argv[i]);
584             }
585         } else if (!strcmp(argv[i], "--tint")) {
586             i++;
587             if (i == argc) {
588                 ERR( "trayer: missing tint parameter value\n");
589                 usage();
590                 exit(1);
591             } else {
592                 p->tintcolor = strtoul(argv[i], NULL, 0);
593             }
594         } else if (!strcmp(argv[i], "--distance")) {
595             i++;
596             if (i == argc) {
597                 ERR( "trayer: missing distance parameter value\n");
598                 usage();
599                 exit(1);
600             } else {
601                 distance = atoi(argv[i]);
602             }
603         } else if (!strcmp(argv[i], "--distancefrom")) {
604             i++;
605             if (i == argc) {
606                 ERR( "trayer: missing distancefrom parameter value\n");
607                 usage();
608                 exit(1);
609             } else {
610                 distancefrom = str2num(distancefrom_pair, argv[i], DISTANCEFROM_NONE);
611             }
612         } else if (!strcmp(argv[i], "--expand")) {
613             i++;
614             if (i == argc) {
615                 ERR( "trayer: missing expand parameter value\n");
616                 usage();
617                 exit(1);
618             } else {
619                 expand = str2num(bool_pair, argv[i], 1);
620             }
621         } else if (!strcmp(argv[i], "--padding")) {
622             i++;
623             if (i == argc) {
624                 ERR( "trayer: missing padding parameter value\n");
625                 usage();
626                 exit(1);
627             } else {
628                 padding = atoi(argv[i]);
629             }
630         } else if (!strcmp(argv[i], "--monitor")) {
631             i++;
632             if (i == argc) {
633                 ERR( "trayer: missing monitor parameter value\n");
634                 usage();
635                 exit(1);
636             } else {
637                 if (g_ascii_isdigit(argv[i][0])) {
638                     p->monitor = atoi(argv[i]);
639                 } else if (!strcmp(argv[i], "primary")) {
640                     p->on_primary = 1;
641                 }
642             }
643         } else if (!strcmp(argv[i], "--iconspacing")) {
644             i++;
645             if (i == argc) {
646                 ERR( "trayer: missing icon padding parameter value\n");
647                 usage();
648                 exit(1);
649             } else {
650                 p->icon_spacing = atoi(argv[i]);
651             }
652         } else {
653             printf("trayer: unknown option - %s\n", argv[i]);
654             usage();
655             exit(1);
656         }
657     }
658     g_return_val_if_fail (p != NULL, 1);
659     if (!panel_start(p)) {
660         ERR( "trayer: can't start panel\n");
661         exit(1);
662     }
663     gtk_main();
664     panel_stop(p);
665     g_free(p);
666 
667     exit(0);
668 }
669 
670