PageRenderTime 147ms CodeModel.GetById 60ms app.highlight 50ms RepoModel.GetById 31ms app.codeStats 0ms

/panel.c

https://bitbucket.org/csgordon/trayer
C | 620 lines | 523 code | 70 blank | 27 comment | 155 complexity | 3cab116f51b035f0898a4b3f14dd4923 MD5 | raw file
  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.1"
 20
 21static gchar version[] = VERSION;
 22int distance=0, distancefrom=DISTANCEFROM_TOP;
 23int expand=1 , padding=0;
 24
 25
 26//#define DEBUG
 27#include "dbg.h"
 28
 29
 30static panel *p;
 31static 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
 45static void set_bg(GtkWidget *widget, panel *p);
 46
 47/****************************************************
 48 *         panel's handlers for WM events           *
 49 ****************************************************/
 50/*
 51static void
 52panel_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
 59static void
 60panel_set_wm_strut(panel *p)
 61{
 62    unsigned int 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
108static GdkFilterReturn 
109panel_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
138static gint 
139panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
140{
141    ENTER;
142    RET(FALSE);
143}
144
145static gint
146panel_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
156static gint
157panel_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
172static gint
173panel_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
203set_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
218static void
219panel_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
229static gboolean
230panel_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
246void
247panel_start_gui(panel *p)
248{
249    ENTER;
250    //gtk_rc_parse_string(transparent_rc);
251    p->topgwin      = gtk_window_new(GTK_WINDOW_TOPLEVEL);
252
253    gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
254    gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
255    gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "trayer");
256    gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
257    g_signal_connect ( G_OBJECT(p->topgwin) , "delete-event" , G_CALLBACK(panel_delete_event) , p);
258    g_signal_connect ( G_OBJECT(p->topgwin) , "destroy-event", G_CALLBACK(panel_destroy_event), p);
259    g_signal_connect ( G_OBJECT (p->topgwin), "size-request" , G_CALLBACK(panel_size_req)  , p);
260    g_signal_connect ( G_OBJECT (p->topgwin), "size-allocate", G_CALLBACK(panel_size_alloc), p);
261
262    if (p->transparent) {
263      g_signal_connect (G_OBJECT (p->topgwin), "configure-event", G_CALLBACK(panel_configure_event), p);
264      g_signal_connect (G_OBJECT (p->topgwin), "style-set", G_CALLBACK( panel_style_set), p);
265    } 
266    gtk_widget_realize(p->topgwin);
267    gdk_window_set_decorations(p->topgwin->window, 0);
268    gtk_widget_set_app_paintable(p->topgwin, TRUE);
269
270    p->lbox = p->my_box_new(FALSE, 0);
271    gtk_container_set_border_width(GTK_CONTAINER(p->lbox), 0);
272    gtk_container_add(GTK_CONTAINER(p->topgwin), p->lbox);
273    gtk_widget_show(p->lbox);
274
275    if (p->allign == ALLIGN_RIGHT) {
276        GtkWidget * expander = p->my_box_new(FALSE, 0);
277        gtk_box_pack_start(GTK_BOX(p->lbox), expander, TRUE, TRUE, 0);
278        gtk_widget_show(expander);
279    }
280
281    p->box = p->my_box_new(FALSE, 1);
282    gtk_container_set_border_width(GTK_CONTAINER(p->box), 1);
283    gtk_box_pack_start(GTK_BOX(p->lbox), p->box, FALSE, TRUE, 0);
284    gtk_widget_show(p->box);
285
286    // get properties on topgwin
287    p->topGdkWindow = gtk_widget_get_window(p->topgwin);
288    p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
289
290    bg_init(gdk_helper_display());
291
292    /* make our window unfocusable */
293    gdk_window_set_accept_focus(p->topGdkWindow,False);
294
295    if (p->setdocktype) {
296        gdk_window_set_type_hint(p->topGdkWindow,GDK_WINDOW_TYPE_HINT_DOCK);
297    }
298
299    Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
300
301    /************************/
302    /* Window Mapping Point */
303    gtk_widget_show_all(p->topgwin);
304    Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
305
306    gdk_window_stick                 ( p->topGdkWindow);
307    gdk_window_set_skip_pager_hint   ( p->topGdkWindow, True );
308    gdk_window_set_skip_taskbar_hint ( p->topGdkWindow, True ); 
309
310    XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), PropertyChangeMask);
311    XSelectInput (gdk_helper_display(), p->topxwin, PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
312    gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
313
314    calculate_position(p, distance,distancefrom);
315    gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
316    if (p->setstrut)
317        panel_set_wm_strut(p);
318
319
320    RET();
321}
322
323static int
324panel_parse_global(panel *p)
325{
326    ENTER;
327    p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
328        ? ORIENT_HORIZ : ORIENT_VERT;
329    if (p->orientation == ORIENT_HORIZ) {
330        p->my_box_new = gtk_hbox_new;
331    } else {
332        p->my_box_new = gtk_vbox_new;
333    }
334    if (p->width < 0)
335        p->width = 100;
336    if (p->widthtype == WIDTH_PERCENT && p->width > 100)
337        p->width = 100;
338    p->heighttype = HEIGHT_PIXEL;
339    if (p->heighttype == HEIGHT_PIXEL) {
340        if (p->height < PANEL_HEIGHT_MIN)
341            p->height = PANEL_HEIGHT_MIN;
342        else if (p->height > PANEL_HEIGHT_MAX)
343            p->height = PANEL_HEIGHT_MAX;
344    }
345    panel_start_gui(p);
346    RET(1);
347}
348
349int
350panel_start(panel *p)
351{
352    /* parse global section */
353    ENTER;
354
355    if (!panel_parse_global(p))
356        RET(0);
357
358    if (!tray_constructor(p))
359        RET(0);
360
361    gtk_widget_show_all(p->topgwin);
362    RET(1);
363}
364
365void panel_stop(panel *p)
366{
367    ENTER;
368
369    tray_destructor(p);
370    XSelectInput (gdk_helper_display(), GDK_ROOT_WINDOW(), NoEventMask);
371    gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_wm_events, p);
372    gtk_widget_destroy(p->topgwin);
373    RET();
374}
375
376void
377usage()
378{
379    ENTER;
380    printf("trayer %s - lightweight GTK2+ systray for UNIX desktops\n", version);
381    printf("Command line options:\n");
382    printf(" -h  -- print this help and exit:\n");
383    printf(" -v  -- print version and exit:\n");
384    printf(" --edge       <left|right|top|bottom|none> (default:bottom) \n");
385    printf(" --align      <left|right|center>          (default:center)\n");
386    printf(" --margin     <number>\n");
387    printf(" --widthtype  <request|pixel|percent>      (default:percent)\n");
388    printf(" --width      <number>                     (default:100)\n");
389    printf(" --heighttype <request|pixel>              (default:pixel)\n");
390    printf(" --height     <number>                     (default:26)\n");
391    printf(" --SetDockType     <true|false>            (default:true)\n");
392    printf(" --SetPartialStrut <true|false>            (default:false)\n");
393    printf(" --transparent     <true|false>            (default:false)\n");
394    printf(" --alpha      <number>                     (default:127)\n");
395    printf(" --tint       <int>\n");
396    printf(" --distance   <number>\n");
397    printf(" --distancefrom <number>\n");
398    printf(" --expand     <false|true>\n");
399    printf(" --padding    <number>\n");
400    printf(" --monitor    <number>                     (default:0)\n");
401}
402    
403void
404handle_error(Display * d, XErrorEvent * ev)
405{
406    char buf[256];
407
408    ENTER;
409    XGetErrorText(gdk_helper_display(), ev->error_code, buf, 256);
410    ERR( "trayer : X error: %s\n", buf);
411    RET();
412}
413
414int
415main(int argc, char *argv[], char *env[])
416{
417    int i;
418
419    ENTER;
420    setlocale(LC_CTYPE, ""); 
421    gtk_init(&argc, &argv);
422    XSetLocaleModifiers(""); 
423    XSetErrorHandler((XErrorHandler) handle_error);
424    // resolve xatoms 
425    resolve_atoms();
426
427    p = g_new0(panel, 1);
428    memset(p, 0, sizeof(panel));
429    p->allign = ALLIGN_CENTER;
430    p->edge = EDGE_BOTTOM;
431    p->widthtype = WIDTH_PERCENT;
432    p->width = 100;
433    p->heighttype = HEIGHT_PIXEL;
434    p->height = PANEL_HEIGHT_DEFAULT;
435    p->setdocktype = 1;
436    p->setstrut = 0;
437    p->transparent = 0;
438    p->alpha = 127;
439    p->tintcolor = 0xFFFFFFFF;
440    p->xtopbg = None;
441    p->monitor = 0;
442
443    for (i = 1; i < argc; i++) {
444        if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
445            usage();
446            exit(0);
447        } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
448            printf("trayer %s\n", version);
449            exit(0);
450        } else if (!strcmp(argv[i], "--edge")) {
451            i++;
452            if (i == argc) {
453                ERR( "trayer: missing edge parameter value\n");
454                usage();
455                exit(1);
456            } else {
457                p->edge = str2num(edge_pair, argv[i], EDGE_NONE);
458            }
459        } else if (!strcmp(argv[i], "--align")) {
460            i++;
461            if (i == argc) {
462                ERR( "trayer: missing align parameter value\n");
463                usage();
464                exit(1);
465            } else {
466                p->allign = str2num(allign_pair, argv[i], ALLIGN_NONE);
467            }
468        } else if (!strcmp(argv[i], "--margin")) {
469            i++;
470            if (i == argc) {
471                ERR( "trayer: missing margin parameter value\n");
472                usage();
473                exit(1);
474            } else {
475                p->margin = atoi(argv[i]);
476            }
477        } else if (!strcmp(argv[i], "--widthtype")) {
478            i++;
479            if (i == argc) {
480                ERR( "trayer: missing widthtype parameter value\n");
481                usage();
482                exit(1);
483            } else {
484                p->widthtype = str2num(width_pair, argv[i], WIDTH_NONE);
485            }
486        } else if (!strcmp(argv[i], "--width")) {
487            i++;
488            if (i == argc) {
489                ERR( "trayer: missing width parameter value\n");
490                usage();
491                exit(1);
492            } else {
493                p->width = atoi(argv[i]);
494            }
495        } else if (!strcmp(argv[i], "--heighttype")) {
496            i++;
497            if (i == argc) {
498                ERR( "trayer: missing heighttype parameter value\n");
499                usage();
500                exit(1);
501            } else {
502                p->heighttype = str2num(height_pair, argv[i], HEIGHT_NONE);
503            }
504        } else if (!strcmp(argv[i], "--height")) {
505            i++;
506            if (i == argc) {
507                ERR( "trayer: missing height parameter value\n");
508                usage();
509                exit(1);
510            } else {
511                p->height = atoi(argv[i]);
512            }
513        } else if (!strcmp(argv[i], "--SetDockType")) {
514            i++;
515            if (i == argc) {
516                ERR( "trayer: missing SetDockType parameter value\n");
517                usage();
518                exit(1);
519            } else {
520                p->setdocktype = str2num(bool_pair, argv[i], 0);
521            }
522        } else if (!strcmp(argv[i], "--SetPartialStrut")) {
523            i++;
524            if (i == argc) {
525                ERR( "trayer: missing SetPartialStrut parameter value\n");
526                usage();
527                exit(1);
528            } else {
529                p->setstrut = str2num(bool_pair, argv[i], 0);
530            }
531        } else if (!strcmp(argv[i], "--transparent")) {
532            i++;
533            if (i == argc) {
534                ERR( "trayer: missing transparent parameter value\n");
535                usage();
536                exit(1);
537            } else {
538                p->transparent = str2num(bool_pair, argv[i], 1);
539            }
540        } else if (!strcmp(argv[i], "--alpha")) {
541            i++;
542            if (i == argc) {
543                ERR( "trayer: missing alpha parameter value\n");
544                usage();
545                exit(1);
546            } else {
547                p->alpha = atoi(argv[i]);
548            }
549        } else if (!strcmp(argv[i], "--tint")) {
550            i++;
551            if (i == argc) {
552                ERR( "trayer: missing tint parameter value\n");
553                usage();
554                exit(1);
555            } else {
556                p->tintcolor = strtoul(argv[i], NULL, 0);
557            }
558        } else if (!strcmp(argv[i], "--distance")) {
559            i++;
560            if (i == argc) {
561                ERR( "trayer: missing distance parameter value\n");
562                usage();
563                exit(1);
564            } else {
565                distance = atoi(argv[i]);
566            }
567        } else if (!strcmp(argv[i], "--distancefrom")) {
568            i++;
569            if (i == argc) {
570                ERR( "trayer: missing distancefrom parameter value\n");
571                usage();
572                exit(1);
573            } else {
574                distancefrom = str2num(distancefrom_pair, argv[i], DISTANCEFROM_NONE);
575            }
576        } else if (!strcmp(argv[i], "--expand")) {
577            i++;
578            if (i == argc) {
579                ERR( "trayer: missing expand parameter value\n");
580                usage();
581                exit(1);
582            } else {
583                expand = str2num(bool_pair, argv[i], 1);
584            }
585        } else if (!strcmp(argv[i], "--padding")) {
586            i++;
587            if (i == argc) {
588                ERR( "trayer: missing padding parameter value\n");
589                usage();
590                exit(1);
591            } else {
592                padding = atoi(argv[i]);
593            }
594        } else if (!strcmp(argv[i], "--monitor")) {
595            i++;
596            if (i == argc) {
597                ERR( "trayer: missing monitor parameter value\n");
598                usage();
599                exit(1);
600            } else {
601                p->monitor = atoi(argv[i]);
602            }
603        } else {
604            printf("trayer: unknown option - %s\n", argv[i]);
605            usage();
606            exit(1);
607        }
608    }
609    g_return_val_if_fail (p != NULL, 1);
610    if (!panel_start(p)) {
611        ERR( "trayer: can't start panel\n");
612        exit(1);
613    }
614    gtk_main();
615    panel_stop(p);
616    g_free(p);
617
618    exit(0);
619}
620