aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am15
-rw-r--r--src/msg.c670
-rw-r--r--src/msg.h20
-rw-r--r--src/panel.c2030
-rw-r--r--src/panel.h312
-rw-r--r--src/panel_app.c597
-rw-r--r--src/panel_app.h92
-rw-r--r--src/panel_menu.c276
-rw-r--r--src/panel_menu.h27
-rw-r--r--src/panel_util.c233
-rw-r--r--src/panel_util.h33
-rw-r--r--src/session.c311
-rw-r--r--src/session.h37
13 files changed, 4653 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..92f9f65
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,15 @@
+PREFIXDIR = $(prefix)
+PKGDATADIR = $(pkgdatadir)
+DATADIR = $(datadir)
+
+INCLUDES = -DDATADIR=\"$(DATADIR)\" -DPKGDATADIR=\"$(PKGDATADIR)\" -DPREFIX=\"$(PREFIXDIR)\" $(LIBMB_CFLAGS)
+
+bin_PROGRAMS = matchbox-panel
+
+matchbox_panel_LDADD = $(LIBMB_LIBS)
+
+matchbox_panel_SOURCES = \
+ panel.c panel_app.c panel_menu.c panel_util.c session.c msg.c \
+ panel.h panel_app.h panel_menu.h panel_util.h session.h msg.h
+
+
diff --git a/src/msg.c b/src/msg.c
new file mode 100644
index 0000000..f213c95
--- /dev/null
+++ b/src/msg.c
@@ -0,0 +1,670 @@
+#include "msg.h"
+
+static MBLayout*
+msg_calc_win_size(MBPanel *d, MBPanelMessageQueue *m, int *w, int *h);
+
+
+/*
+static int
+_get_text_length(MBPanel *d, char *str, int cnt)
+{
+#ifdef USE_XFT
+ XGlyphInfo extents;
+ XftTextExtents8(d->dpy, d->msg_font, (unsigned char *) str,
+ cnt, &extents);
+ return extents.width;
+#else
+ return XTextWidth(d->msg_font, str, cnt);
+#endif
+}
+*/
+
+static unsigned long
+_get_server_time(MBPanel *d)
+{
+ XEvent xevent;
+ char c = 'a';
+
+ XChangeProperty (d->dpy, d->win_root,
+ d->atoms[ATOM_MB_DOCK_TIMESTAMP],
+ d->atoms[ATOM_MB_DOCK_TIMESTAMP],
+ 8, PropModeReplace, &c, 1);
+
+ for (;;) {
+ XMaskEvent(d->dpy, PropertyChangeMask, &xevent);
+ if (xevent.xproperty.atom == d->atoms[ATOM_MB_DOCK_TIMESTAMP])
+ {
+ return xevent.xproperty.time;
+ }
+ }
+}
+
+static void
+_send_tray_context_message(MBPanel *panel,
+ Window win)
+{
+ XEvent ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = win;
+ ev.xclient.message_type = panel->atoms[ATOM_MB_SYSTEM_TRAY_CONTEXT];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = _get_server_time(panel);
+
+ XSendEvent(panel->dpy, win, False, NoEventMask, &ev);
+ XSync(panel->dpy, False);
+}
+
+
+MBPanelMessageQueue*
+msg_new(MBPanel *dock, XClientMessageEvent *e)
+{
+ MBPanelMessageQueue *m;
+ MBPanelApp *sender;
+
+ if ((sender = panel_app_get_from_window(dock, e->window )) == NULL)
+ return NULL;
+
+ m = (MBPanelMessageQueue *)malloc(sizeof(MBPanelMessageQueue));
+ m->sender = sender;
+
+ m->starttime = e->data.l[0];
+ m->timeout = e->data.l[2];
+
+ m->total_msg_length = e->data.l[3];
+ m->id = e->data.l[4];
+ m->data = (unsigned char *)malloc(sizeof(unsigned char)
+ *(m->total_msg_length+1));
+ m->current_msg_length = 0;
+ m->pending = False;
+ m->next = NULL;
+
+ if (dock->msg_queue_start == NULL)
+ {
+ DBG("queue is empty\n");
+ dock->msg_queue_start = dock->msg_queue_end = m;
+ } else {
+ DBG("queue is not empty\n");
+ dock->msg_queue_end->next = m;
+ dock->msg_queue_end = m;
+ }
+
+ return m;
+}
+
+void
+msg_destroy(MBPanel *panel, MBPanelMessageQueue *msg)
+{
+ MBPanelMessageQueue *msg_q;
+ if (panel->msg_queue_start == msg)
+ {
+ panel->msg_queue_start = msg->next;
+ } else {
+ for(msg_q=panel->msg_queue_start; msg_q->next != NULL; msg_q=msg_q->next)
+ {
+ if (msg_q->next == msg)
+ {
+ msg_q->next = msg->next;
+ break;
+ }
+ }
+ }
+
+ if (msg->extra_context_data) XFree(msg->extra_context_data);
+ free(msg->data);
+ free(msg);
+}
+
+void
+msg_add_data(MBPanel *d, XClientMessageEvent *e)
+{
+ MBPanelMessageQueue *m;
+
+ for(m=d->msg_queue_start; m != NULL; m=m->next)
+ {
+ if (m->sender->win == e->window)
+ {
+ if ( (m->total_msg_length - m->current_msg_length) > 20)
+ {
+ memcpy(&m->data[m->current_msg_length],e->data.b,sizeof(char)*20);
+ m->current_msg_length += 20;
+ } else {
+ memcpy(&m->data[m->current_msg_length],e->data.b,
+ (m->total_msg_length-m->current_msg_length) );
+ m->current_msg_length = m->total_msg_length;
+ m->data[m->total_msg_length] = '\0';
+
+ m->pending = True;
+ }
+ return;
+ }
+ }
+}
+
+void
+msg_win_create(MBPanel *panel,
+ MBPanelMessageQueue *msg)
+{
+ int msg_win_x = 0, msg_win_y = 0, msg_win_w = 0, msg_win_h = 0,
+ box_x_offset = 0, box_y_offset = 0, arrow_offset = 0, cnt = 0,
+ box_w, box_h;
+
+ int x, y, txt_v_offset;
+ unsigned char r, g, b, fr, fg, fb;
+
+ MBPixbufImage *img_backing = NULL;
+ MBDrawable *tmp_drw;
+
+ Pixmap mask;
+ GC mask_gc;
+ XSetWindowAttributes attr;
+ XWindowAttributes root_attr;
+ XWMHints *wm_hints;
+ long winmask;
+ MBLayout *layout;
+
+ /*
+#ifdef USE_XFT
+ XftDraw *xftdraw;
+ XftColor txt_xftcol;
+ XRenderColor colortmp;
+#endif
+ */
+
+ layout = msg_calc_win_size(panel, msg, &msg_win_w, &msg_win_h);
+
+ msg_win_h += (2*MSG_WIN_Y_PAD);
+
+ box_w = msg_win_w; box_h = msg_win_h;
+
+ XGetWindowAttributes(panel->dpy, panel->win_root, &root_attr);
+
+#define ARROW_SIZE 4
+#define MSG_TEXT_MARGIN 10
+
+ switch (panel->orientation)
+ {
+ case East:
+ msg_win_w += ARROW_SIZE;
+ msg_win_x = panel->x - msg_win_w - 5;
+ break;
+ case West:
+ msg_win_w += ARROW_SIZE;
+ box_x_offset += ARROW_SIZE;
+ msg_win_x = panel->x + panel->w + 5;
+ break;
+ case South:
+ msg_win_h += ARROW_SIZE;
+ msg_win_y = panel->y - msg_win_h - 5;
+ break;
+ case North:
+ msg_win_h += ARROW_SIZE;
+ box_y_offset += ARROW_SIZE;
+ msg_win_y = panel->y + panel->h + 5;
+ break;
+ }
+
+ printf("%s() called()\n", __func__);
+
+ if (PANEL_IS_VERTICAL(panel))
+ {
+ arrow_offset = msg_win_h / 2;
+ msg_win_y = panel->y + msg->sender->y + (msg->sender->h/2) - arrow_offset;
+
+ if (msg_win_y < 0)
+ {
+ msg_win_y = 5; /* a little margin to display top */
+ arrow_offset = msg->sender->y + (msg->sender->h/2);
+ }
+
+ if (msg_win_y + msg_win_h > panel->y + panel->h)
+ {
+ /* reposition with a bit of margin - 5px */
+ msg_win_y = (panel->y + panel->h) - msg_win_h - 5;
+ arrow_offset = panel->y + msg->sender->y - msg_win_y + (msg->sender->h/2);
+ }
+ }
+ else
+ {
+ arrow_offset = msg_win_w / 2;
+ msg_win_x = panel->x + msg->sender->x + (msg->sender->w/2) - arrow_offset;
+
+ if (msg_win_x < 0)
+ {
+ msg_win_x = 5;
+ arrow_offset = msg->sender->x + (msg->sender->w/2);
+ }
+
+ if (msg_win_x + msg_win_w > panel->x + panel->w)
+ {
+ msg_win_x = (panel->x + panel->w) - msg_win_w - 5;
+ arrow_offset = panel->x + msg->sender->x - msg_win_x + (msg->sender->w/2);
+ }
+ }
+
+ attr.event_mask = ButtonPressMask|ButtonReleaseMask|ExposureMask;
+ attr.background_pixel = BlackPixel(panel->dpy, panel->screen);
+ attr.do_not_propagate_mask = ButtonPressMask|ButtonReleaseMask;
+ winmask = CWBackPixel|CWEventMask|CWDontPropagate;
+
+ if (panel->use_overide_wins)
+ {
+ winmask |= CWOverrideRedirect;
+ attr.override_redirect = True;
+ }
+
+ panel->msg_win = XCreateWindow(panel->dpy, panel->win_root,
+ msg_win_x,
+ msg_win_y,
+ msg_win_w,
+ msg_win_h, 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ winmask,
+ &attr);
+
+ XChangeProperty(panel->dpy, panel->msg_win,
+ panel->atoms[ATOM_WM_WINDOW_TYPE],
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *)
+ &panel->atoms[ATOM_WM_WINDOW_TYPE_SPLASH], 1);
+
+ wm_hints = XAllocWMHints();
+ wm_hints->input = False;
+ wm_hints->flags = InputHint;
+ XSetWMHints(panel->dpy, panel->msg_win, wm_hints);
+
+ tmp_drw = mb_drawable_new(panel->pb, msg_win_w, msg_win_h);
+
+ img_backing = mb_pixbuf_img_rgba_new(panel->pb, msg_win_w, msg_win_h);
+
+ mask = XCreatePixmap(panel->dpy, panel->win_root, msg_win_w, msg_win_h, 1 );
+ mask_gc = XCreateGC(panel->dpy, mask, 0, 0 );
+
+ XSetForeground(panel->dpy, mask_gc, WhitePixel( panel->dpy, panel->screen ));
+ XFillRectangle(panel->dpy, mask, mask_gc, 0, 0, msg_win_w, msg_win_h );
+ XSetForeground(panel->dpy, mask_gc, BlackPixel( panel->dpy, panel->screen ));
+
+ /*
+ * - fill entire block with forground color
+ * - alpha clear part
+ * - draw arrow part
+ * - curve corners ?
+ */
+
+ r = mb_col_red(panel->msg_col);
+ g = mb_col_green(panel->msg_col);
+ b = mb_col_blue(panel->msg_col);
+
+ fr = mb_col_red(panel->msg_fg_col);
+ fg = mb_col_green(panel->msg_fg_col);
+ fb = mb_col_blue(panel->msg_fg_col);
+
+ mb_pixbuf_img_fill (panel->pb, img_backing, r, g, b, 255);
+
+ /* border */
+
+ /* top/bottom */
+ for (x = box_x_offset; x < box_x_offset + box_w; x++)
+ {
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, box_y_offset,
+ fr, fg, fb);
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x,
+ box_h + box_y_offset - 1,
+ fr, fg, fb);
+ }
+
+ /* sides */
+ for (y = box_y_offset; y < box_y_offset + box_h; y++)
+ {
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, box_x_offset, y,
+ fr, fg, fb);
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing,
+ box_w + box_x_offset - 1, y,
+ fr, fg, fb);
+ }
+
+ /* arrow */
+
+ switch (panel->orientation)
+ {
+ case East:
+
+ for (x= box_w; x < msg_win_w; x++)
+ for (y=0; y < box_h; y++)
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+
+ XSetForeground( panel->dpy, mask_gc,
+ WhitePixel( panel->dpy, panel->screen ));
+
+ for (x= msg_win_w - 1; x > msg_win_w - ARROW_SIZE - 2 ; x--)
+ {
+ for (y = arrow_offset - cnt; y <= arrow_offset + cnt; y++)
+ {
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+ if ( y == (arrow_offset - cnt) || y == (arrow_offset + cnt) )
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y,
+ fr, fg, fb);
+ else
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y, r,g,b);
+ }
+ cnt++;
+ }
+
+ break;
+
+ case West:
+
+ for (x=0; x<ARROW_SIZE; x++)
+ for (y=0; y < msg_win_h; y++)
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+
+ XSetForeground( panel->dpy, mask_gc,
+ WhitePixel( panel->dpy, panel->screen ));
+
+ for (x=0; x<ARROW_SIZE + 1; x++)
+ {
+ for (y = arrow_offset - cnt; y <= arrow_offset + cnt; y++)
+ {
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+ if ( y == (arrow_offset - cnt) || y == (arrow_offset + cnt) )
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y,
+ fr, fg, fb);
+ else
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y, r,g,b);
+ }
+ cnt++;
+ }
+
+ break;
+
+ case South:
+
+ for (y=msg_win_h-ARROW_SIZE; y < msg_win_h; y++)
+ for (x=0; x < msg_win_w; x++)
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+
+ XSetForeground( panel->dpy, mask_gc,
+ WhitePixel( panel->dpy, panel->screen ));
+
+ for (y=msg_win_h; y >= msg_win_h - ARROW_SIZE - 1; y--)
+ {
+ for (x = arrow_offset - cnt; x <= arrow_offset + cnt; x++)
+ {
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+ if ( x == (arrow_offset - cnt) || x == (arrow_offset + cnt) )
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y,
+ fr, fg, fb);
+ else
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y, r,g,b);
+ }
+ cnt++;
+ }
+
+ break;
+
+ case North:
+
+ for (y=0; y < ARROW_SIZE; y++)
+ for (x=0; x < msg_win_w; x++)
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+
+ XSetForeground( panel->dpy, mask_gc,
+ WhitePixel( panel->dpy, panel->screen ));
+
+ for (y=0; y < ARROW_SIZE + 1; y++)
+ {
+ for (x = arrow_offset - cnt; x <= arrow_offset + cnt; x++)
+ {
+ XDrawPoint(panel->dpy, mask, mask_gc, x, y);
+
+ if ( x == (arrow_offset - cnt) || x == (arrow_offset + cnt) )
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y,
+ fr, fg, fb);
+ else
+ mb_pixbuf_img_plot_pixel(panel->pb, img_backing, x, y, r,g,b);
+ }
+
+ cnt++;
+ }
+
+ break;
+
+ }
+
+ /* Render picture to pixmap */
+ mb_pixbuf_img_render_to_drawable(panel->pb, img_backing,
+ mb_drawable_pixmap(tmp_drw),
+ 0, 0);
+
+
+ mb_font_set_color(panel->msg_font, panel->msg_fg_col);
+
+ txt_v_offset = MSG_WIN_Y_PAD + box_y_offset;
+
+ /*
+ i = strlen(msg->sender->name);
+ while (_get_text_length(panel, msg->sender->name, i) > ( box_w + ( 2 * MSG_TEXT_MARGIN ))
+ && i > 0)
+ i--;
+ */
+
+ /* Title */
+
+ XSetForeground(panel->dpy, panel->msg_gc, mb_col_xpixel(panel->msg_fg_col));
+
+ mb_font_render_simple (panel->msg_font,
+ tmp_drw,
+ MSG_TEXT_MARGIN + box_x_offset,
+ txt_v_offset,
+ box_w, /* XXX - TEXT_MARGIN ? */
+ (unsigned char *)msg->sender->name,
+ MB_ENCODING_UTF8,
+ 0);
+
+ /* close box */
+
+ XDrawRectangle(panel->dpy, mb_drawable_pixmap(tmp_drw), panel->msg_gc,
+ box_x_offset + box_w - MSG_TEXT_MARGIN - mb_font_get_height(panel->msg_font),
+ txt_v_offset,
+ mb_font_get_height(panel->msg_font),
+ mb_font_get_height(panel->msg_font) );
+
+ XDrawLine(panel->dpy, mb_drawable_pixmap(tmp_drw), panel->msg_gc,
+ box_x_offset + box_w - MSG_TEXT_MARGIN - mb_font_get_height(panel->msg_font),
+ txt_v_offset ,
+ box_x_offset + box_w - MSG_TEXT_MARGIN,
+ txt_v_offset + mb_font_get_height(panel->msg_font));
+
+ XDrawLine(panel->dpy, mb_drawable_pixmap(tmp_drw), panel->msg_gc,
+ box_x_offset + box_w - MSG_TEXT_MARGIN - mb_font_get_height(panel->msg_font),
+ txt_v_offset + mb_font_get_height(panel->msg_font),
+ box_x_offset + box_w - MSG_TEXT_MARGIN,
+ txt_v_offset );
+
+ /* Title underline */
+
+ XDrawLine(panel->dpy, mb_drawable_pixmap(tmp_drw), panel->msg_gc,
+ box_x_offset + MSG_TEXT_MARGIN / 2 ,
+ txt_v_offset + mb_font_get_height(panel->msg_font) + ( MSG_LINE_SPC / 2 ),
+ box_x_offset + box_w - (MSG_TEXT_MARGIN / 2),
+ txt_v_offset + mb_font_get_height(panel->msg_font) + ( MSG_LINE_SPC / 2 ) );
+
+ /* Forward render postion on */
+ txt_v_offset += mb_font_get_height(panel->msg_font) + MSG_LINE_SPC;
+
+ /* render msg text */
+ mb_layout_render (layout, tmp_drw, MSG_TEXT_MARGIN + box_x_offset, txt_v_offset, 0);
+
+ txt_v_offset += mb_layout_height(layout);
+
+ /* Context button, if applicable */
+ if (msg->extra_context_data)
+ {
+ int context_width = mb_font_get_txt_width ( panel->msg_font,
+ msg->extra_context_data,
+ strlen(msg->extra_context_data),
+ MB_ENCODING_UTF8);
+
+ XSetForeground( panel->dpy, panel->msg_gc, mb_col_xpixel(panel->msg_link_col));
+
+ panel->msg_context_y1 = txt_v_offset;
+ panel->msg_context_y2 = txt_v_offset + mb_font_get_height(panel->msg_font);
+
+ mb_font_set_color(panel->msg_font, panel->msg_link_col);
+
+ mb_font_render_simple (panel->msg_font,
+ tmp_drw,
+ MSG_TEXT_MARGIN + box_x_offset,
+ txt_v_offset,
+ box_w,
+ (unsigned char *)msg->extra_context_data,
+ MB_ENCODING_UTF8,
+ 0);
+
+ /* underline */
+
+ XDrawLine(panel->dpy, mb_drawable_pixmap(tmp_drw), panel->msg_gc,
+ MSG_TEXT_MARGIN + box_x_offset,
+ txt_v_offset + mb_font_get_height(panel->msg_font),
+ MSG_TEXT_MARGIN + box_x_offset + context_width,
+ txt_v_offset + mb_font_get_height(panel->msg_font));
+ }
+
+
+ XSetWindowBackgroundPixmap(panel->dpy, panel->msg_win,
+ mb_drawable_pixmap(tmp_drw));
+
+
+ mb_drawable_unref(tmp_drw);
+
+ XShapeCombineMask( panel->dpy, panel->msg_win, ShapeBounding, 0, 0, mask, ShapeSet);
+
+ XMapWindow(panel->dpy, panel->msg_win);
+ XFree(wm_hints);
+
+ mb_pixbuf_img_free(panel->pb, img_backing);
+ XFreePixmap(panel->dpy, mask);
+}
+
+
+void
+msg_handle_events(MBPanel *panel, XEvent *e)
+{
+ MBPanelMessageQueue *msg = NULL;
+
+ for(msg=panel->msg_queue_start; msg != NULL; msg=msg->next)
+ {
+ if (msg->pending)
+ {
+ if (panel->msg_win)
+ {
+ XDestroyWindow(panel->dpy, panel->msg_win);
+ panel->msg_win = None;
+ }
+
+ panel->msg_starttime = msg->starttime;
+ panel->msg_timeout = msg->timeout;
+ panel->msg_win_sender = msg->sender;
+
+ panel->msg_has_context = False;
+
+ if ((msg->extra_context_data = util_get_utf8_prop(panel, panel->msg_win_sender->win, panel->atoms[ATOM_MB_SYSTEM_TRAY_CONTEXT])) != NULL)
+ panel->msg_has_context = True;
+
+ msg_win_create(panel, msg);
+
+ msg_destroy(panel, msg);
+
+ return;
+ }
+ }
+
+ if (panel->msg_win)
+ {
+ switch (e->type)
+ {
+ case Expose:
+ break;
+ case ButtonRelease:
+ if ( e->xbutton.window == panel->msg_win)
+ {
+ if (panel->msg_has_context
+ && e->xbutton.y >= panel->msg_context_y1
+ && e->xbutton.y <= panel->msg_context_y2)
+ {
+ _send_tray_context_message(panel, panel->msg_win_sender->win);
+ }
+
+ XDestroyWindow(panel->dpy, panel->msg_win);
+ panel->msg_win = None;
+ }
+ break;
+ }
+ }
+}
+
+void
+msg_handle_timeouts(MBPanel *d)
+{
+ if (d->msg_win)
+ {
+ if (d->msg_timeout) /* NON ZERO */
+ {
+ if ((d->msg_starttime+d->msg_timeout) < _get_server_time(d))
+ {
+ XDestroyWindow(d->dpy, d->msg_win);
+ d->msg_win = None;
+ return;
+ }
+ }
+ }
+}
+
+static MBLayout*
+msg_calc_win_size(MBPanel *panel, MBPanelMessageQueue *m, int *w, int *h)
+{
+ MBLayout *layout;
+
+ int title_width = 0, context_width = 0;
+
+ *w = 0;
+ *h = 0;
+
+ layout = mb_layout_new ();
+
+ mb_layout_set_font(layout, panel->msg_font);
+ mb_layout_set_text(layout, m->data, MB_ENCODING_UTF8);
+
+ mb_layout_get_geometry(layout, w, h);
+
+ /* title + line */
+ *h += (mb_font_get_height(panel->msg_font) + MSG_LINE_SPC) ;
+
+ title_width = mb_font_get_txt_width(panel->msg_font,
+ m->sender->name, strlen(m->sender->name),
+ MB_ENCODING_UTF8)
+ + (2 * mb_font_get_height(panel->msg_font));
+
+ if (title_width > *w) *w = title_width;
+
+ if (m->extra_context_data)
+ {
+ context_width = mb_font_get_txt_width(panel->msg_font,
+ m->extra_context_data,
+ strlen(m->extra_context_data),
+ MB_ENCODING_UTF8);
+
+ if (context_width > *w) *w = context_width;
+
+ *h += mb_font_get_height(panel->msg_font);
+ }
+
+ *w += ( 2 * MSG_TEXT_MARGIN );
+
+ return layout;
+}
+
+
diff --git a/src/msg.h b/src/msg.h
new file mode 100644
index 0000000..5fe90ef
--- /dev/null
+++ b/src/msg.h
@@ -0,0 +1,20 @@
+#ifndef _MSG_H_
+#define _MSG_H_
+
+#include <string.h>
+
+#include "panel.h"
+#include "panel_app.h"
+
+#define MSG_WIN_Y_PAD 5
+#define MSG_BUB_POLY 15
+
+#define MSG_LINE_SPC 8
+
+MBPanelMessageQueue* msg_new(MBPanel *dock, XClientMessageEvent *e);
+void msg_destroy(MBPanel *d, MBPanelMessageQueue *m);
+void msg_add_data(MBPanel *d, XClientMessageEvent *e);
+void msg_handle_events(MBPanel *d, XEvent *e);
+void msg_handle_timeouts(MBPanel *d);
+
+#endif
diff --git a/src/panel.c b/src/panel.c
new file mode 100644
index 0000000..1c4d691
--- /dev/null
+++ b/src/panel.c
@@ -0,0 +1,2030 @@
+/*
+ * mbpanel
+ *
+ * A 'system tray' - Matthew Allum <mallum@handhelds.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "panel.h"
+#include "msg.h"
+
+MBPanel *G_panel = NULL;
+
+#define DEFAULT_MSG_FGCOL "black"
+#define DEFAULT_MSG_BGCOL "yellow"
+#define DEFAULT_MSG_BGURGCOL "orange"
+
+#ifdef USE_XSETTINGS
+
+/*
+ XX = system_tray_id;
+
+/MATCHBOX/PANEL/XX/ORIENTATION north|south|east|west
+/MATCHBOX/PANEL/XX/BACKGROUND default|rgb:XXX|pxm:XXX|trans:XXX
+ Gtk/FontName
+*/
+
+#define XSET_UNKNOWN 0
+#define XSET_GTK_FONT 1
+
+static void
+panel_xsettings_notify_cb (const char *name,
+ XSettingsAction action,
+ XSettingsSetting *setting,
+ void *data)
+{
+ MBPanel *panel = (MBPanel *)data;
+ int i = 0;
+ int key = XSET_UNKNOWN;
+
+ struct _mb_xsettings { char *name; int value; } mb_xsettings[] = {
+ { "Gtk/FontName", XSET_GTK_FONT },
+ { NULL, -1 }
+ };
+
+ while( mb_xsettings[i].name != NULL )
+ {
+ if (!strcmp(name, mb_xsettings[i].name)
+ && setting != NULL /* XXX set to NULL when action deleted */
+ && setting->type == XSETTINGS_TYPE_STRING )
+ {
+ key = mb_xsettings[i].value;
+ break;
+ }
+ i++;
+ }
+
+ if (key == XSET_UNKNOWN) return;
+
+ switch (action)
+ {
+ case XSETTINGS_ACTION_NEW:
+ case XSETTINGS_ACTION_CHANGED:
+ switch (key)
+ {
+ case XSET_GTK_FONT:
+ if (setting->data.v_string && strlen(setting->data.v_string))
+ {
+ /* This will be overidden ( hopefully ) by any theme.desktop
+ * setting.
+ */
+ DBG("%s() setting XSET_GTK_FONT: '%s'\n", __func__,
+ setting->data.v_string);
+ /* mb_menu_set_font (panel->mbmenu, setting->data.v_string); */
+ mb_font_set_from_string(panel->msg_font, setting->data.v_string);
+
+ }
+ break;
+
+ }
+ case XSETTINGS_ACTION_DELETED:
+ /* Do nothing for now */
+ break;
+ }
+}
+
+#endif
+
+
+void
+panel_handle_full_panel (MBPanel *panel, MBPanelApp *bad_papp)
+{
+
+ /* For now we just killoff the client */
+
+ DBG("%s() killing winbow id %li\n", __func__, bad_papp->win);
+
+ XKillClient(panel->dpy, bad_papp->win); /* XXX should probably make this
+ kill more effectively */
+ panel_app_destroy (panel, bad_papp);
+}
+
+void /* XXX maybe better to add this to panel_menu_add_remove_item */
+panel_update_client_list_prop (MBPanel *panel)
+{
+ MBPanelApp *papp = NULL;
+ MBPanelApp *papp_heads[] = { panel->apps_start_head,
+ panel->apps_end_head,
+ NULL };
+ int i = 0, app_cnt = 0, cnt = 0;
+ Window *wins = NULL;
+
+ DBG("%s() called\n", __func__);
+
+ /* Count number of applets docked */
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+ while( papp != NULL)
+ {
+ if (!papp->ignore) app_cnt++;
+ papp = papp->next;
+ }
+ i++;
+ }
+
+ if (app_cnt == 0)
+ {
+ /* delete prop ?? */
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_NET_CLIENT_LIST] ,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)NULL, 0);
+ return;
+ }
+
+ i = 0;
+ wins = malloc(sizeof(Window)*app_cnt);
+
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+
+ if (i == 1)
+ papp = panel_app_list_get_last(panel, panel->apps_end_head);
+
+ while( papp != NULL)
+ {
+ if (!papp->ignore)
+ {
+ wins[cnt++] = papp->win;
+ }
+
+ if (i == 1)
+ {
+ papp = panel_app_list_get_prev (panel, papp,
+ &panel->apps_end_head);
+ }
+ else papp = papp->next;
+ }
+ i++;
+ }
+
+
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_NET_CLIENT_LIST],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)wins, app_cnt);
+
+ free(wins);
+
+}
+
+
+void /* show/hiden the panel */
+panel_toggle_visibilty(MBPanel *d)
+{
+
+#define PANEL_HIDDEN_SIZE 6
+
+
+ static int panel_orig_size;
+ MBPanelApp *papp = NULL;
+ MBPanelApp *papp_heads[] = { d->apps_start_head,
+ d->apps_end_head,
+ NULL };
+ int i = 0;
+
+ DBG("%s() called, x: %i, y: %i, w: %i, h: %i\n", __func__,
+ d->x, d->y, d->w, d->h);
+
+ if (d->is_hidden)
+ {
+
+ if (PANEL_IS_VERTICAL(d))
+ {
+ XMoveResizeWindow(d->dpy, d->win, d->x, d->y,
+ panel_orig_size, d->h );
+ d->w = panel_orig_size;
+ } else {
+ XMoveResizeWindow(d->dpy, d->win, d->x, d->y, d->w,
+ panel_orig_size);
+ d->h = panel_orig_size;
+ }
+
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+ while( papp != NULL)
+ {
+ XMapWindow(d->dpy, papp->win);
+ panel_app_move_to (d, papp,
+ panel_app_get_offset (d, papp));
+ papp->ignore_unmap--;
+ papp = papp->next;
+ }
+ i++;
+ }
+
+ d->is_hidden = False;
+
+ } else {
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+ while( papp != NULL)
+ {
+ XUnmapWindow(d->dpy, papp->win);
+ papp->ignore_unmap++;
+ papp = papp->next;
+ }
+ i++;
+ }
+
+ if (PANEL_IS_VERTICAL(d))
+ {
+ XMoveResizeWindow(d->dpy, d->win, d->x, d->y,
+ PANEL_HIDDEN_SIZE, d->h );
+ panel_orig_size = d->w;
+ } else {
+ XMoveResizeWindow(d->dpy, d->win, d->x, d->y,
+ d->w, PANEL_HIDDEN_SIZE);
+ panel_orig_size = d->h;
+ }
+ d->is_hidden = True;
+ }
+}
+
+void
+panel_set_bg(MBPanel *panel, int bg_type, char *bg_spec)
+{
+ MBPixbufImage *img_tmp, *img_bg;
+ int dx, dy, dw, dh;
+
+ Pixmap tmp_pxm;
+ char xprop_def[32] = { 0 };
+ char *tmp_path = NULL;
+
+ if (panel->bg_spec) free(panel->bg_spec);
+ panel->bg_spec = strdup(bg_spec);
+ panel->bg_type = bg_type;
+
+ DBG("%s() bg_spec: %s, type %i\n", __func__, panel->bg_spec, panel->bg_type);
+
+ XGrabServer(panel->dpy);
+
+ switch (bg_type)
+ {
+ case BG_PIXMAP:
+ if (bg_spec[0] != '/' && panel->theme_path != NULL)
+ {
+ tmp_path = alloca( sizeof(char) * (strlen(panel->theme_path) + strlen(bg_spec)));
+ sprintf(tmp_path, "%s/%s", panel->theme_path, bg_spec);
+ }
+ else tmp_path = bg_spec;
+
+ if ((img_tmp = mb_pixbuf_img_new_from_file(panel->pb, tmp_path)) == NULL)
+ {
+ fprintf(stderr, "mbdock: failed to load %s\n", bg_spec);
+ panel_set_bg(panel, BG_SOLID_COLOR, DEFAULT_COLOR_SPEC);
+ return;
+ }
+
+ img_bg = mb_pixbuf_img_new(panel->pb, panel->w, panel->h);
+
+ /* scale for panel height ? */
+ if ( (img_tmp->height != panel->h && !PANEL_IS_VERTICAL(panel))
+ || (img_tmp->width != panel->w && PANEL_IS_VERTICAL(panel)) )
+ {
+ MBPixbufImage *img_scaled;
+ img_scaled = mb_pixbuf_img_scale(panel->pb, img_tmp,
+ img_tmp->width,
+ PANEL_IS_VERTICAL(panel) ?
+ panel->w : panel->h);
+ mb_pixbuf_img_free(panel->pb, img_tmp);
+ img_tmp = img_scaled;
+ }
+
+ /* rotate */
+ if (PANEL_IS_VERTICAL(panel))
+ {
+ MBPixbufImage *img_rot;
+ img_rot = mb_pixbuf_img_transform (panel->pb, img_tmp,
+ MBPIXBUF_TRANS_ROTATE_90);
+
+ mb_pixbuf_img_free(panel->pb, img_tmp);
+ img_tmp = img_rot;
+ }
+
+ for (dy=0; dy < panel->h; dy += img_tmp->height)
+ for (dx=0; dx < panel->w; dx += img_tmp->width)
+ {
+ if ( (dx + img_tmp->width) > panel->w )
+ dw = img_tmp->width - ((dx + img_tmp->width)-panel->w);
+ else
+ dw = img_tmp->width;
+
+ if ( (dy + img_tmp->height) > panel->h )
+ dh = img_tmp->height-((dy + img_tmp->height)-panel->h);
+ else
+ dh = img_tmp->height;
+ mb_pixbuf_img_copy(panel->pb, img_bg, img_tmp,
+ 0, 0, dw, dh, dx, dy);
+ }
+
+ mb_pixbuf_img_free(panel->pb, img_tmp);
+
+ if (panel->bg_pxm != None)
+ XFreePixmap(panel->dpy, panel->bg_pxm);
+
+ panel->bg_pxm = XCreatePixmap(panel->dpy, panel->win_root,
+ panel->w, panel->h,
+ panel->pb->depth );
+
+ mb_pixbuf_img_render_to_drawable(panel->pb, img_bg, panel->bg_pxm, 0, 0);
+
+ mb_pixbuf_img_free(panel->pb, img_bg);
+
+ XSetWindowBackgroundPixmap(panel->dpy, panel->win, panel->bg_pxm);
+ XClearWindow(panel->dpy, panel->win);
+
+ snprintf(xprop_def, 32, "pxm:%li", panel->bg_pxm);
+ panel->root_pixmap_id = 0;
+ break;
+ case BG_SOLID_COLOR:
+ if (XParseColor(panel->dpy,
+ DefaultColormap(panel->dpy, panel->screen),
+ bg_spec,
+ &panel->xcol ))
+ {
+
+ XAllocColor(panel->dpy,
+ DefaultColormap(panel->dpy, panel->screen),
+ &panel->xcol);
+
+ XSetWindowBackground(panel->dpy, panel->win,
+ panel->xcol.pixel);
+ XClearWindow(panel->dpy, panel->win);
+
+ if (panel->bg_pxm != None)
+ XFreePixmap(panel->dpy, panel->bg_pxm);
+ panel->bg_pxm = None;
+
+ snprintf(xprop_def, 32, "rgb:%li", panel->xcol.pixel);
+ }
+ panel->root_pixmap_id = 0;
+ break;
+ case BG_TRANS:
+ tmp_pxm = util_get_root_pixmap(panel);
+ if (tmp_pxm != None)
+ {
+ int trans_level = 0;
+
+ if (bg_spec) trans_level = atoi(bg_spec);
+
+ DBG("%s() Getting root pixmap\n", __func__);
+
+ if (panel->bg_pxm != None) XFreePixmap(panel->dpy, panel->bg_pxm);
+
+ panel->bg_pxm = XCreatePixmap(panel->dpy, panel->win_root,
+ panel->w, panel->h,
+ panel->pb->depth );
+
+ img_tmp = mb_pixbuf_img_new_from_drawable(panel->pb,
+ tmp_pxm, None,
+ panel->x, panel->y,
+ panel->w, panel->h);
+ if (img_tmp == NULL)
+ {
+ XFreePixmap(panel->dpy, panel->bg_pxm);
+ fprintf(stderr, "Failed to get root pixmap id\n");
+ panel_set_bg(panel, BG_SOLID_COLOR, DEFAULT_COLOR_SPEC);
+ return;
+ }
+
+ DBG("%s() First pixel of root looks like %i, %i, %i, %i\n",
+ __func__, img_tmp->rgba[0], img_tmp->rgba[1],
+ img_tmp->rgba[2], img_tmp->rgba[3]);
+
+ if (trans_level > 0)
+ for (dx = 0; dx < panel->w; dx++)
+ for (dy = 0; dy < panel->h; dy++)
+ mb_pixbuf_img_plot_pixel_with_alpha(panel->pb,
+ img_tmp, dx, dy,
+ 255, 255, 255,
+ trans_level);
+
+
+ mb_pixbuf_img_render_to_drawable(panel->pb, img_tmp,
+ panel->bg_pxm, 0, 0);
+
+ mb_pixbuf_img_free(panel->pb, img_tmp);
+
+
+ XSetWindowBackgroundPixmap(panel->dpy, panel->win,
+ panel->bg_pxm);
+ XClearWindow(panel->dpy, panel->win);
+
+ snprintf(xprop_def, 32, "pxm:%li", panel->bg_pxm);
+
+ } else {
+ fprintf(stderr, "Failed to get root pixmap id\n");
+ panel->root_pixmap_id = -1;
+ panel_set_bg(panel, BG_SOLID_COLOR, DEFAULT_COLOR_SPEC);
+ return;
+ }
+
+ break;
+ }
+
+ if (xprop_def)
+ {
+ DBG("setting _MB_PANEL_BG to %s\n", xprop_def);
+
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_MB_PANEL_BG],
+ XA_STRING, 8,
+ PropModeReplace, xprop_def,
+ strlen(xprop_def));
+ }
+
+ XUngrabServer(panel->dpy);
+
+ XSync(panel->dpy, False);
+
+}
+
+Bool
+panel_set_theme_from_root_prop(MBPanel *panel)
+{
+ Atom realType;
+ unsigned long n;
+ unsigned long extra;
+ int format;
+ int status;
+ char * value;
+ struct stat stat_info;
+ char panel_cfg[256];
+
+ DBG("%s() called\n", __func__);
+
+ if ( panel->use_themes == False )
+ {
+ DBG("%s() panel themeing disabled by command line options\n", __func__ );
+ return False;
+ }
+
+ status = XGetWindowProperty(panel->dpy, panel->win_root,
+ panel->atoms[ATOM_MB_THEME],
+ 0L, 512L, False,
+ AnyPropertyType, &realType,
+ &format, &n, &extra,
+ (unsigned char **) &value);
+
+ if (status != Success || value == 0
+ || *value == 0 || n == 0)
+ {
+ DBG("%s() no _MB_THEME set on root window\n", __func__ );
+ return False;
+ } else {
+
+ int i = 0;
+ MBPanelApp *papp = NULL;
+ MBPanelApp *papp_heads[] = { panel->apps_start_head,
+ panel->apps_end_head,
+ NULL };
+
+ strcpy(panel_cfg, value);
+ strcat(panel_cfg, "/theme.desktop");
+
+ if (stat(panel_cfg, &stat_info) != -1)
+ {
+ MBDotDesktop *theme = NULL;
+ theme = mb_dotdesktop_new_from_file(panel_cfg);
+ if (theme)
+ {
+ if (panel->theme_path) free(panel->theme_path);
+ panel->theme_path = strdup(value);
+
+ /* Different theme values for panel in titlebar */
+ if (panel->want_titlebar_dest)
+ {
+ if (mb_dotdesktop_get(theme, "TitlebarDockBgColor"))
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR,
+ mb_dotdesktop_get(theme, "TitlebarDockBgColor"));
+ }
+
+ if (mb_dotdesktop_get(theme, "TitlebarDockBgPixmap"))
+ {
+ panel_set_bg(panel, BG_PIXMAP,
+ mb_dotdesktop_get(theme, "TitlebarDockBgPixmap"));
+ }
+
+ /* Newer settings */
+
+ if (mb_dotdesktop_get(theme, "TitlebarPanelBgColor"))
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR,
+ mb_dotdesktop_get(theme, "TitlebarPanelBgColor"));
+ }
+
+ if (mb_dotdesktop_get(theme, "TitlebarPanelBgPixmap"))
+ {
+ panel_set_bg(panel, BG_PIXMAP,
+ mb_dotdesktop_get(theme, "TitlebarPanelBgPixmap"));
+ }
+
+
+ }
+ else
+ {
+
+ /*
+ * FIXME: Need to phase out the Dock prefix to panel
+ */
+
+ if (mb_dotdesktop_get(theme, "DockBgColor"))
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR,
+ mb_dotdesktop_get(theme, "DockBgColor"));
+ }
+ if (mb_dotdesktop_get(theme, "DockBgTrans"))
+ {
+ panel_set_bg(panel, BG_TRANS,
+ mb_dotdesktop_get(theme, "DockBgTrans"));
+ }
+ if (mb_dotdesktop_get(theme, "DockBgPixmap"))
+ {
+ panel_set_bg(panel, BG_PIXMAP,
+ mb_dotdesktop_get(theme, "DockBgPixmap"));
+ }
+
+ /* Newer setting below */
+
+ if (mb_dotdesktop_get(theme, "PanelBgColor"))
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR,
+ mb_dotdesktop_get(theme, "PanelBgColor"));
+ }
+ if (mb_dotdesktop_get(theme, "PanelBgTrans"))
+ {
+ panel_set_bg(panel, BG_TRANS,
+ mb_dotdesktop_get(theme, "PanelBgTrans"));
+ }
+ if (mb_dotdesktop_get(theme, "PanelBgPixmap"))
+ {
+ panel_set_bg(panel, BG_PIXMAP,
+ mb_dotdesktop_get(theme, "PanelBgPixmap"));
+ }
+
+
+ }
+
+ if (mb_dotdesktop_get(theme, "PanelMsgBgCol"))
+ util_xcol_from_spec(panel, panel->msg_col,
+ mb_dotdesktop_get(theme, "PanelMsgBgCol"));
+ else
+ util_xcol_from_spec(panel, panel->msg_col,
+ DEFAULT_MSG_BGCOL);
+
+
+
+
+ if (mb_dotdesktop_get(theme, "PanelMsgBgUrgentCol"))
+ util_xcol_from_spec(panel, panel->msg_urgent_col,
+ mb_dotdesktop_get(theme,
+ "PanelMsgBgUrgentCol"));
+ else
+ util_xcol_from_spec(panel, panel->msg_urgent_col,
+ DEFAULT_MSG_BGURGCOL);
+
+ if (mb_dotdesktop_get(theme, "PanelMsgFgCol"))
+ util_xcol_from_spec(panel, panel->msg_fg_col,
+ mb_dotdesktop_get(theme,
+ "PanelMsgFgCol"));
+ else
+ util_xcol_from_spec(panel, panel->msg_fg_col,
+ DEFAULT_MSG_FGCOL);
+ mb_dotdesktop_free(theme);
+
+ }
+ }
+
+ if (value) XFree(value);
+
+ status = XGetWindowProperty(panel->dpy, panel->win_root,
+ panel->atoms[ATOM_MB_THEME_NAME],
+ 0L, 512L, False,
+ AnyPropertyType, &realType,
+ &format, &n, &extra,
+ (unsigned char **) &value);
+
+ if (status && value)
+ {
+ if (panel->theme_name) free(panel->theme_name);
+ panel->theme_name = strdup(value);
+ }
+
+ if (value) XFree(value);
+
+ /* Now retheme the panel menu */
+ panel_menu_init(panel);
+
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+ while( papp != NULL )
+ {
+ panel_menu_update_remove_items(panel);
+ papp = papp->next;
+ }
+ i++;
+ }
+
+ return True;
+ }
+ return False;
+}
+
+void
+panel_usage(char *bin_name)
+{
+ fprintf(stderr, "%s usage: %s [Options...]\n"
+ "Where options are;\n"
+ "-display, -d <X11 Display name>\n"
+ "-geometry, -g Use --size / --orientation instead.\n"
+ "--id <int> Panel ID\n"
+ "--size, -s <int> width/height of dock in pixels\n"
+ "--orientation <north|east|south|west>\n"
+ "--default-apps, -da <app list> comma seperated list of apps to\n"
+ " add to a tray when no session exists\n"
+ "--margin-start <+int> initial app offset in pixels (panel start)\n"
+ "--margin-end <+int> initial app offset in pixels (panel end)\n"
+ "--titlebar Request panel in titlebar - see docs for limitations\n"
+ "--no-session, -ns No session saving.\n"
+ "--no-menu, -nm No popup menu\n"
+ "--no-flip, -nf On a display rotation, stop the panel from\n"
+ " From rotating itself too\n"
+ "--overide-bubbles, -o\n\n"
+ "Background options:\n"
+ "--bgcolor, -c <color spec>\n"
+ "--bgpixmap, -b <image file>\n"
+ "--bgtrans, -bt <'yes'|transparency percentage>\n"
+ "*NOTE* setting the background here will disable the effect\n"
+ " of any external theme changes. \n"
+ , bin_name, bin_name);
+ exit(1);
+}
+
+/* XEMBED */
+
+int
+panel_get_map_state(MBPanel *d, MBPanelApp *c)
+{
+ Atom realType;
+ unsigned long n;
+ unsigned long extra;
+ int format;
+ int status;
+ CARD32 * value = NULL;
+ int result = -1;
+
+ status = XGetWindowProperty(d->dpy, c->win,
+ d->atoms[ATOM_XEMBED_INFO],
+ 0L, 10L,
+ 0, XA_ATOM, &realType, &format,
+ &n, &extra, (unsigned char **) &value);
+ if (status == Success)
+ {
+ if (realType == XA_CARDINAL && format == 32)
+ {
+ /*
+ printf("VERSION: %i\n", value[0]);
+ printf("MAPPED: %i\n", value[1]);
+ */
+
+ result = (int)value[1];
+
+ }
+ }
+
+ if (value) XFree(value);
+
+ return result;
+}
+
+void panel_send_xembed_message(
+ MBPanel *d,
+ MBPanelApp *c,
+ long message, /* message opcode */
+ long detail, /* message detail */
+ long data1, /* message data 1 */
+ long data2 /* message data 2 */
+ ){
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = c->win;
+ ev.xclient.message_type = d->atoms[ATOM_XEMBED_MESSAGE];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = CurrentTime;
+ ev.xclient.data.l[1] = message;
+ ev.xclient.data.l[2] = detail;
+ ev.xclient.data.l[3] = data1;
+ ev.xclient.data.l[4] = data2;
+ XSendEvent(d->dpy, c->win, False, NoEventMask, &ev);
+ XSync(d->dpy, False);
+}
+
+void panel_send_manage_message( MBPanel *d )
+{
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = d->win_root;
+ ev.xclient.message_type = d->atoms[ATOM_MANAGER];
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = CurrentTime;
+ ev.xclient.data.l[1] = d->atoms[ATOM_SYSTEM_TRAY];
+ ev.xclient.data.l[2] = d->win;
+
+ XSendEvent(d->dpy, d->win_root, False, StructureNotifyMask, &ev);
+ XSync(d->dpy, False);
+}
+
+
+
+/* Events */
+
+void
+panel_handle_button_event(MBPanel *panel, XButtonEvent *e)
+{
+ XEvent ev;
+ int done = 0;
+ struct timeval then, now;
+
+ DBG("%s() called, subwindow : %li\n", __func__, e->subwindow );
+
+ if (!panel->use_menu) return; /* menu disabled */
+
+ if (e->window != panel->win) return;
+
+ if (panel->is_hidden)
+ {
+ panel_toggle_visibilty(panel);
+ return;
+ }
+
+ gettimeofday(&then, NULL);
+ while (!done) {
+ if (XCheckMaskEvent(panel->dpy,ButtonReleaseMask, &ev))
+ if (ev.type == ButtonRelease) done=1;
+ gettimeofday(&now, NULL);
+ if ( (now.tv_usec-then.tv_usec) > (panel->click_time*1000) )
+ done=2;
+ }
+
+ if (done == 2 && !mb_menu_is_active(panel->mbmenu))
+ {
+ int dpy_h = DisplayHeight(panel->dpy, panel->screen);
+ util_get_mouse_position(panel, &panel->click_x, &panel->click_y);
+ mb_menu_activate(panel->mbmenu,
+ (panel->click_x-5 < 0) ? 2 : panel->click_x-5,
+ (panel->click_y+5 > dpy_h) ? dpy_h-2 : panel->click_y+5);
+ }
+}
+
+void
+panel_handle_expose(MBPanel *panel, XExposeEvent *e)
+{
+ ;
+}
+
+void
+panel_handle_dock_request(MBPanel *panel, Window win)
+{
+ int app_origin_dist = 0;
+ char *cmd_str = NULL;
+ MBPanelApp *new_papp = NULL;
+
+ util_get_command_str_from_win(panel, win, &cmd_str); /* cmd_str freed l8r */
+
+ if (session_preexisting_win_matches_wanted(panel, win, cmd_str))
+ {
+ app_origin_dist = panel->session_init_offset;
+ session_preexisting_clear_current(panel);
+ }
+
+ new_papp = panel_app_new(panel, win, cmd_str);
+
+ if (new_papp)
+ {
+ XSelectInput(panel->dpy, new_papp->win, PropertyChangeMask );
+
+ /* tell app its docked - panel app should now map its self */
+ panel_send_xembed_message(panel, new_papp,
+ XEMBED_EMBEDDED_NOTIFY,
+ 0, panel->win, 0);
+
+ /* sent when it gets focus */
+ panel_send_xembed_message(panel, new_papp,
+ XEMBED_WINDOW_ACTIVATE,
+ 0,0,0);
+
+ XMapWindow(panel->dpy, new_papp->win);
+ new_papp->mapped = True;
+
+ panel_menu_update_remove_items(panel);
+ }
+
+ session_save(panel);
+
+ session_preexisting_start_next(panel);
+}
+
+void
+panel_handle_client_message(MBPanel *panel, XClientMessageEvent *e)
+{
+ DBG("%s() called\n", __func__ );
+ if (e->message_type
+ == panel->atoms[ATOM_SYSTEM_TRAY_OPCODE])
+ {
+ DBG("%s() got system tray message\n", __func__ );
+ switch (e->data.l[1])
+ {
+ case SYSTEM_TRAY_REQUEST_DOCK:
+ DBG("%s() is SYSTEM_TRAY_REQUEST_DOCK\n", __func__ );
+ panel_handle_dock_request(panel, e->data.l[2]);
+ break;
+ case SYSTEM_TRAY_BEGIN_MESSAGE:
+ DBG("%s() is SYSTEM_TRAY_BEGIN_MESSAGE\n", __func__ );
+ msg_new(panel, e);
+ break;
+ case SYSTEM_TRAY_CANCEL_MESSAGE:
+ DBG("%s() is SYSTEM_TRAY_CANCEL_MESSAGE\n", __func__ );
+ break;
+ }
+ return;
+ }
+
+ if (e->message_type
+ == panel->atoms[ATOM_MB_COMMAND])
+ {
+ switch (e->data.l[0])
+ {
+ case MB_CMD_PANEL_TOGGLE_VISIBILITY:
+ panel_toggle_visibilty(panel);
+ break;
+ case MB_CMD_PANEL_SIZE:
+ case MB_CMD_PANEL_ORIENTATION:
+ default:
+ break;
+ }
+
+ }
+
+ if (e->message_type
+ == panel->atoms[ATOM_NET_SYSTEM_TRAY_MESSAGE_DATA])
+ {
+ DBG("%s() got system tray message _data_\n", __func__ );
+ msg_add_data(panel, e);
+ return;
+ }
+
+ if (e->message_type
+ == panel->atoms[ATOM_WM_DELETE_WINDOW])
+ {
+ util_cleanup_children(0);
+ }
+
+ return;
+}
+
+void
+panel_handle_property_notify(MBPanel *panel, XPropertyEvent *e)
+{
+ MBPanelApp *papp;
+
+ if (e->atom == panel->atoms[ATOM_XEMBED_INFO])
+ {
+ int i;
+ papp = panel_app_get_from_window(panel, e->window);
+ DBG("%s() got XEMBED_INFO property notify for %s\n",
+ __func__, papp->name );
+ if (papp != NULL)
+ {
+ i = panel_get_map_state(panel, papp);
+ if (i == 1)
+ {
+ XMapRaised(panel->dpy, papp->win);
+ papp->mapped = True;
+ }
+ if (i == 0)
+ {
+ XUnmapWindow(panel->dpy, papp->win);
+ papp->mapped = False;
+ }
+ }
+ return;
+ }
+
+ if (e->atom == panel->atoms[ATOM_MB_THEME])
+ {
+ panel_set_theme_from_root_prop(panel);
+ return;
+ }
+
+ if (e->atom == panel->atoms[ATOM_XROOTPMAP_ID]
+ && panel->root_pixmap_id != 0)
+ {
+ panel_set_bg(panel, BG_TRANS, panel->bg_trans);
+ return;
+ }
+
+ if (e->atom == panel->atoms[ATOM_MB_REQ_CLIENT_ORDER])
+ {
+ panel_reorder_apps(panel);
+ }
+}
+
+static Bool
+get_xevent_timed(Display* dpy, XEvent* event_return, struct timeval *tv)
+{
+ if (tv == NULL)
+ {
+ XNextEvent(dpy, event_return);
+ return True;
+ }
+
+ XFlush(dpy);
+
+ if (XPending(dpy) == 0)
+ {
+ int fd = ConnectionNumber(dpy);
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(fd, &readset);
+ if (select(fd+1, &readset, NULL, NULL, tv) == 0)
+ {
+ return False;
+ } else {
+ XNextEvent(dpy, event_return);
+ return True;
+ }
+ } else {
+ XNextEvent(dpy, event_return);
+ return True;
+ }
+}
+
+void
+panel_main(MBPanel *panel)
+{
+ MBPanelApp *papp;
+ XEvent an_event;
+ int xfd;
+ Bool had_rotation = False;
+
+ XSelectInput (panel->dpy, panel->win, StructureNotifyMask|ExposureMask|
+ SubstructureRedirectMask|SubstructureNotifyMask|
+ ButtonPressMask|ButtonReleaseMask|PointerMotionMask|
+ PropertyChangeMask);
+
+ XSelectInput (panel->dpy, panel->win_root,
+ PropertyChangeMask|StructureNotifyMask);
+
+ xfd = ConnectionNumber (panel->dpy);
+
+ XFlush(panel->dpy);
+
+ while(1)
+ {
+ struct timeval tvt;
+ tvt.tv_usec = 500;
+ tvt.tv_sec = 0;
+
+ if (get_xevent_timed(panel->dpy, &an_event, &tvt))
+ {
+#ifdef USE_XSETTINGS
+ if (panel->xsettings_client != NULL)
+ xsettings_client_process_event(panel->xsettings_client, &an_event);
+#endif
+ mb_menu_handle_xevent(panel->mbmenu, &an_event);
+ switch (an_event.type)
+ {
+ case ButtonPress:
+ panel_handle_button_event(panel, &an_event.xbutton);
+ break;
+ case ClientMessage:
+ panel_handle_client_message(panel, &an_event.xclient);
+ break;
+ case PropertyNotify:
+ panel_handle_property_notify(panel, &an_event.xproperty);
+ break;
+ case MapRequest:
+ break;
+ case UnmapNotify:
+ /* window should unmap ... we destroy it */
+ papp = panel_app_get_from_window(panel,
+ an_event.xunmap.window);
+ if (papp && !papp->ignore_unmap)
+ {
+ panel_app_destroy(panel, papp);
+
+ /* remove any connected message windows */
+ if (panel->msg_win && panel->msg_win_sender == papp)
+ {
+ XDestroyWindow(panel->dpy, panel->msg_win);
+ panel->msg_win = None;
+ }
+
+ /*
+ * We set an alarm here, so the session file is only
+ * updated after a couple fo seconds.
+ * This is done so if the xserver is closing and bringing
+ * down all the clients. Its very likely it'll kill
+ * a panelapp before the panel, and we dont really want it
+ * to be refmoved from the session file.
+ */
+ alarm(3);
+ }
+ break;
+ case Expose:
+ panel_handle_expose(panel, &an_event.xexpose);
+ break;
+ case DestroyNotify:
+ break;
+ case ConfigureRequest:
+ panel_app_handle_configure_request(panel,
+ &an_event.xconfigurerequest);
+ break;
+ case ConfigureNotify:
+ if (an_event.xconfigure.window == panel->win_root)
+ {
+ had_rotation = True;
+ DBG("%s() **** HAD ROTATION ***\n", __func__);
+ break;
+ }
+
+ if (an_event.xconfigure.window == panel->win)
+ {
+ DBG("%s(): configureNotify on panel\n", __func__);
+ /* These can be confused by a flip */
+ if (an_event.xconfigure.send_event)
+ break;
+
+ if (panel->w != an_event.xconfigure.width
+ || panel->h != an_event.xconfigure.height)
+ {
+ int diff = 0;
+ MBPanelApp *papp = NULL;
+
+ if (panel->ignore_next_config)
+ {
+ panel->ignore_next_config = False;
+ break;
+ }
+
+ if (panel->use_flip && had_rotation)
+ {
+ /* Flip if are length is changed
+ XXX a little hacky XXXX
+ */
+ int dpy_w, dpy_h;
+ XWindowAttributes root_attr;
+
+ XGetWindowAttributes(panel->dpy,
+ panel->win_root,
+ &root_attr);
+
+ dpy_w = root_attr.width;
+ dpy_h = root_attr.height;
+
+ had_rotation = False;
+
+ if ((PANEL_IS_VERTICAL(panel)
+ && (an_event.xconfigure.width == panel->w)
+ )
+ ||
+ (!PANEL_IS_VERTICAL(panel)
+ && (an_event.xconfigure.height == panel->h)
+ /* && (an_event.xconfigure.width == dpy_w)
+ && dpy_w != panel->w */ )
+ )
+ {
+
+ DBG("%s() flipping ....\n", __func__);
+
+ panel->ignore_next_config = True;
+
+ switch (panel->orientation)
+ {
+ case South:
+ panel_change_orientation(panel, East,
+ dpy_w, dpy_h);
+ break;
+ case North:
+ panel_change_orientation(panel, West,
+ dpy_w, dpy_h);
+ break;
+ case West:
+ panel_change_orientation(panel, North,
+ dpy_w, dpy_h);
+ break;
+ case East:
+ panel_change_orientation(panel, South,
+ dpy_w, dpy_h);
+ break;
+ }
+ break;
+ }
+ }
+
+ if (PANEL_IS_VERTICAL(panel))
+ {
+ diff = an_event.xconfigure.height - panel->h;
+ if (an_event.xconfigure.y > panel->y)
+ papp = panel->apps_start_head;
+ else
+ papp = panel->apps_end_head;
+ } else {
+ diff = an_event.xconfigure.width - panel->w;
+ if (an_event.xconfigure.x > panel->x)
+ papp = panel->apps_start_head;
+ else
+ papp = panel->apps_end_head;
+ }
+
+ panel->w = an_event.xconfigure.width;
+ panel->h = an_event.xconfigure.height;
+
+ panel_apps_nudge (panel, papp, diff);
+
+ /* Nake sure bg gets updated */
+ if (!(panel->use_flip && had_rotation))
+ {
+ char *tmp_str = NULL;
+ if (panel->bg_spec)
+ tmp_str = strdup(panel->bg_spec) ;
+ panel_set_bg(panel, panel->bg_type, tmp_str);
+ if (tmp_str) free(tmp_str);
+ }
+
+ // panel_apps_rescale (panel, panel->apps_start_head);
+ // panel_apps_rescale (panel, panel->apps_end_head);
+ }
+
+ panel->x = an_event.xconfigure.x;
+ panel->y = an_event.xconfigure.y;
+
+ DBG("%s() config notify, got x: %i , y: %i w: %i h: %i \n",
+ __func__,
+ an_event.xconfigure.x,
+ an_event.xconfigure.y,
+ an_event.xconfigure.width,
+ an_event.xconfigure.height);
+
+ DBG("%s() panel is now x: %i , y: %i w: %i h: %i \n",
+ __func__, panel->x, panel->y,
+ panel->w, panel->h );
+ }
+ break;
+ }
+ msg_handle_events(panel, &an_event);
+ }
+ session_preexisting_handle_timeouts(panel);
+ msg_handle_timeouts(panel);
+ }
+}
+
+static void
+panel_orientation_set_hint (MBPanel *panel)
+{
+ int is_vertical[1] = { 0 };
+
+ if (PANEL_IS_VERTICAL(panel)) is_vertical[0] = 1;
+
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_NET_SYSTEM_TRAY_ORIENTATION],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)is_vertical , 1);
+}
+
+
+void
+panel_change_orientation(MBPanel *panel,
+ MBPanelOrientation new_orientation,
+ int dpy_w, int dpy_h)
+{
+ char *tmp_str = NULL;
+
+ XUnmapWindow(panel->dpy, panel->win);
+
+ if ( ( (panel->orientation == East || panel->orientation == West)
+ && (new_orientation == North || new_orientation == South) )
+ ||
+ ( (panel->orientation == North || panel->orientation == South)
+ && (new_orientation == East || new_orientation == West ) )
+ )
+ {
+ MBPanelApp *papp_heads[] = { panel->apps_start_head,
+ panel->apps_end_head,
+ NULL };
+ MBPanelApp *papp_cur = NULL;
+ int i = 0;
+
+ panel->x = 0;
+ panel->y = 0;
+ panel->h = panel->default_panel_size;
+ panel->w = dpy_w;
+
+ switch (new_orientation)
+ {
+ case South:
+ panel->y = dpy_h - panel->h;
+ break;
+ case North:
+ break;
+ case West:
+ panel->w = panel->default_panel_size;
+ panel->h = dpy_h;
+ break;
+ case East:
+ panel->w = panel->default_panel_size;
+ panel->h = dpy_h;
+ panel->x = dpy_w - panel->w;
+ break;
+ }
+
+ panel->orientation = new_orientation;
+
+ panel_orientation_set_hint(panel);
+
+ DBG("%s() setting panel x: %i , y: %i w: %i h: %i \n",
+ __func__, panel->x, panel->y,
+ panel->w, panel->h );
+
+ XMoveResizeWindow( panel->dpy, panel->win, panel->x, panel->y,
+ panel->w, panel->h );
+
+ /* move_to() will reposition each app */
+ while (i < 2)
+ {
+ papp_cur = papp_heads[i];
+ DBG("%s() moveing to, cur is i: %i ( %p )\n",
+ __func__, i, papp_cur);
+
+ while (papp_cur != NULL)
+ {
+ int tmp;
+ tmp = papp_cur->w;
+ papp_cur->w = papp_cur->h;
+ papp_cur->h = tmp;
+
+ if (panel->orientation == North || panel->orientation == South)
+ {
+ papp_cur->x = papp_cur->offset;
+ papp_cur->y = (panel->h - papp_cur->h) / 2;
+ }
+ else
+ {
+ papp_cur->y = papp_cur->offset;
+ papp_cur->x = (panel->w - papp_cur->w) / 2;
+ }
+
+ XMoveWindow(panel->dpy, papp_cur->win,
+ papp_cur->x, papp_cur->y);
+
+ panel_app_deliver_config_event(panel, papp_cur);
+ papp_cur = papp_cur->next;
+ }
+ i++;
+ }
+ }
+ else
+ {
+ switch (new_orientation)
+ {
+ case South:
+ panel->y = dpy_h - panel->h;
+ break;
+ case North:
+ panel->y = 0;
+ break;
+ case West:
+ panel->x = 0;
+ break;
+ case East:
+ panel->x = dpy_w - panel->w;
+ break;
+ }
+
+ panel->orientation = new_orientation;
+
+ panel_orientation_set_hint(panel);
+
+ XMoveResizeWindow( panel->dpy, panel->win, panel->x, panel->y,
+ panel->w, panel->h );
+ }
+
+ if (panel->bg_spec) tmp_str = strdup(panel->bg_spec) ;
+ panel_set_bg(panel, panel->bg_type, tmp_str);
+ if (tmp_str) free(tmp_str);
+
+ XMapWindow(panel->dpy, panel->win);
+ XMapSubwindows(panel->dpy, panel->win);
+
+}
+
+
+
+void
+panel_reorder_apps(MBPanel *panel)
+{
+ MBPanelApp *papp, *papp_tmp;
+ int i, watermark = 0, offset = 0;
+
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after = 0;
+ unsigned char *prop = NULL;
+ int n_wins;
+ Window *wins;
+
+ if (XGetWindowProperty (panel->dpy, panel->win,
+ panel->atoms[ATOM_MB_REQ_CLIENT_ORDER],
+ 0, 1000L, False, XA_WINDOW,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop) != Success)
+ return;
+
+ wins = (Window *)prop;
+ n_wins = (int)nitems;
+
+ papp = panel->apps_start_head;
+
+ while( papp != NULL)
+ {
+ watermark++;
+ papp = papp->next;
+ }
+
+ DBG("%s() watermark is %i\n", __func__, watermark);
+
+ for (i =0; i<n_wins; i++)
+ {
+ papp = panel_app_get_from_window(panel, wins[i]);
+
+ if (papp)
+ {
+ MBPanelApp *found_head = NULL;
+ /* find where it currently is */
+ papp_tmp = panel->apps_start_head;
+
+ DBG("%s() %i looping for %s\n", __func__, i, papp->name);
+
+ while( papp_tmp != NULL)
+ {
+ if (papp == papp_tmp)
+ {
+ found_head = panel->apps_start_head;
+ break;
+ }
+
+ papp_tmp = papp_tmp->next;
+ }
+
+ if (!found_head)
+ {
+ papp_tmp = panel->apps_end_head;
+
+ while( papp_tmp != NULL)
+ {
+ if (papp == papp_tmp)
+ {
+ found_head = panel->apps_end_head;
+ break;
+ }
+
+ papp_tmp = papp_tmp->next;
+ }
+ }
+
+ if (found_head)
+ {
+ if (found_head == panel->apps_start_head)
+ {
+ DBG("%s() %i found head is start\n", __func__, i );
+ panel_app_list_remove (panel, papp, &panel->apps_start_head);
+ }
+ else
+ {
+ DBG("%s() %i found head is end\n", __func__, i );
+ panel_app_list_remove (panel, papp, &panel->apps_end_head);
+
+ }
+
+ papp->next = NULL;
+
+ if (!watermark || (watermark && i >= watermark))
+ {
+ DBG("%s() %i prepending at end\n", __func__, i );
+
+ /*
+ if (found_head != panel->apps_end_head) switched lists
+ panel_app_list_append(panel, &panel->apps_end_head, papp);
+ else
+ */
+ panel->apps_end_head = panel_app_list_prepend(panel, panel->apps_end_head, papp);
+ papp->gravity = PAPP_GRAVITY_END;
+ //panel_app_add_end(panel, papp);
+ }
+ else
+ {
+ DBG("%s() %i appending at start\n", __func__, i );
+ panel_app_list_append(panel, &panel->apps_start_head, papp);
+ //panel_app_add_start(panel, papp);
+ papp->gravity = PAPP_GRAVITY_START;
+ }
+
+
+ }
+ else DBG("%s() %i not found head !!!!\n", __func__, i );
+ }
+ }
+
+ papp = panel->apps_start_head;
+
+ offset = panel->margin_start;
+
+ DBG("%s() start list:\n", __func__ );
+
+ while( papp != NULL)
+ {
+
+ DBG("%s() %s moving to %i\n", __func__, papp->name, offset );
+
+ if (PANEL_IS_VERTICAL(panel))
+ papp->y = offset;
+ else
+ papp->x = offset;
+
+ papp->offset = offset;
+
+ XMoveWindow(panel->dpy, papp->win, papp->x, papp->y);
+
+ panel_app_deliver_config_event(panel, papp);
+
+ offset += ( panel_app_get_size(panel, papp) + panel->padding );
+
+ papp = papp->next;
+ }
+
+ papp = panel->apps_end_head;
+
+ DBG("%s() end list:\n", __func__ );
+
+ if (papp)
+ {
+ offset = ( PANEL_IS_VERTICAL(panel) ? panel->h : panel->w ) - panel->margin_end;
+
+ while( papp != NULL)
+ {
+ offset -= ( panel_app_get_size(panel, papp) + panel->padding );
+
+ DBG("%s() %s moving to %i\n", __func__, papp->name, offset );
+
+ if (PANEL_IS_VERTICAL(panel))
+ papp->y = offset;
+ else
+ papp->x = offset;
+
+ papp->offset = offset;
+
+ XMoveWindow(panel->dpy, papp->win, papp->x, papp->y);
+
+ panel_app_deliver_config_event(panel, papp);
+
+ papp = papp->next;
+ }
+ }
+
+ session_save(panel);
+ panel_menu_update_remove_items(panel);
+ panel_update_client_list_prop(panel);
+
+}
+
+MBPanel
+*panel_init(int argc, char *argv[])
+{
+ int panel_length;
+ XGCValues gv;
+ XSetWindowAttributes dattr;
+ unsigned long dattr_flags = CWBackPixel;
+ XSizeHints size_hints;
+
+ unsigned long wm_struct_vals[4];
+
+ char *geometry_str = NULL;
+ char *color_def = NULL;
+ char *bg_pixmap_def = NULL;
+ char *display_name = (char *)getenv("DISPLAY");
+
+ char tray_atom_spec[128] = { 0 };
+ char tray_id_env_str[16] = { 0 };
+
+ /* MBPanelApp *papp_menu_button = NULL; */
+ MBPanel *panel;
+
+ int panel_border_sz = 0;
+ char *want_trans = NULL;
+
+ char win_name[64] = { 0 };
+ /*
+#ifdef USE_XFT
+ XRenderColor colortmp;
+#endif
+ */
+
+ int i = 0, j = 0;
+
+ struct {
+ char *name;
+ MBPanelOrientation orientation;
+ } orientation_lookup[] = {
+ { "north", North },
+ { "south", South },
+ { "east", East },
+ { "west", West },
+ { NULL, North }
+ };
+
+ XSetErrorHandler(util_handle_xerror);
+
+ panel = NEW(MBPanel);
+ memset(panel, sizeof(MBPanel), 0);
+
+ /* defualts */
+
+ panel->padding = 2;
+ panel->use_session = True;
+ panel->use_alt_session_defaults = False;
+ panel->use_menu = True;
+ panel->click_time = 400;
+ panel->use_overide_wins = False;
+ panel->orientation = South;
+ panel->system_tray_id = 0;
+ panel->use_flip = True;
+ panel->default_panel_size = 0;
+ panel->session_cur_gravity = PAPP_GRAVITY_START;
+ panel->theme_name = NULL;
+ panel->theme_path = NULL;
+ panel->apps_start_head = NULL;
+ panel->apps_end_head = NULL;
+ panel->ignore_next_config = False;
+ panel->margin_start = 2;
+ panel->margin_end = 2;
+ panel->bg_spec = NULL;
+ panel->want_titlebar_dest = False;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ display_name = argv[i];
+ continue;
+ }
+ if (!strcmp ("--no-session", argv[i]) || !strcmp ("-ns", argv[i])) {
+ panel->use_session = False;
+ continue;
+ }
+ if (!strcmp ("--titlebar", argv[i]) || !strcmp ("-tb", argv[i])) {
+ panel->want_titlebar_dest = True;
+ continue;
+ }
+
+ if (!strcmp ("--default-apps", argv[i]) || !strcmp ("-da", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ if (!strcmp(argv[i], "none"))
+ session_set_defaults(panel, strdup(""));
+ else
+ session_set_defaults(panel, argv[i]);
+ continue;
+ }
+
+ if (!strcmp ("--no-menu", argv[i]) || !strcmp ("-nm", argv[i])) {
+ panel->use_menu = False;
+ continue;
+ }
+ if (!strcmp ("--overide-bubbles", argv[i]) || !strcmp ("-o", argv[i])) {
+ panel->use_overide_wins = True;
+ continue;
+ }
+ if (!strcmp ("--no-flip", argv[i])) {
+ panel->use_flip = False;
+ continue;
+ }
+ if (!strcmp ("--bgcolor", argv[i]) || !strcmp ("-c", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ color_def = argv[i];
+ continue;
+ }
+ if (strstr (argv[i], "-geometry") || !strcmp ("-g", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ fprintf(stderr,"mbdock: -geometry is depreciated, please consider --size and --orientation instead\n");
+ geometry_str = argv[i];
+ continue;
+ }
+ if (strstr (argv[i], "--size") || !strcmp ("-s", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ panel->default_panel_size = atoi(argv[i]);
+ if (panel->default_panel_size < 1) panel_usage (argv[0]);
+ continue;
+ }
+ if (strstr (argv[i], "--margin-start")) {
+ if (++i>=argc) panel_usage (argv[0]);
+ panel->margin_start = atoi(argv[i]);
+ if (panel->margin_start < 1) panel_usage (argv[0]);
+ continue;
+ }
+ if (strstr (argv[i], "--margin-end")) {
+ if (++i>=argc) panel_usage (argv[0]);
+ panel->margin_end = atoi(argv[i]);
+ if (panel->margin_end < 1) panel_usage (argv[0]);
+ continue;
+ }
+ if (!strcmp ("--bgpixmap", argv[i]) || !strcmp ("-b", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ bg_pixmap_def = argv[i];
+ continue;
+ }
+ if (!strcmp ("--bgtrans", argv[i]) || !strcmp ("-bt", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ want_trans = argv[i];
+ continue;
+ }
+ if (!strcmp ("--id", argv[i]) || !strcmp ("-i", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ panel->system_tray_id = atoi(argv[i]);
+ continue;
+
+ }
+ if (!strcmp ("--border", argv[i])) {
+ if (++i>=argc) panel_usage (argv[0]);
+ panel_border_sz = atoi(argv[i]);
+ continue;
+ }
+ if (!strcmp ("--orientation", argv[i])) {
+ Bool found = False;
+ if (++i>=argc) panel_usage (argv[0]);
+ j = 0;
+ while (orientation_lookup[j].name != NULL)
+ {
+ if (!strcasecmp(orientation_lookup[j].name, argv[i]))
+ {
+ panel->orientation = orientation_lookup[j].orientation;
+ found = True;
+ }
+ j++;
+ }
+ if (found) continue;
+ }
+ panel_usage(argv[0]);
+ }
+
+ if ((panel->dpy = XOpenDisplay(display_name)) == NULL)
+ {
+ fprintf(stderr, "%s: failed to open display", argv[0]);
+ exit(1);
+ }
+
+ panel->screen = DefaultScreen(panel->dpy);
+ panel->win_root = RootWindow(panel->dpy, panel->screen);
+
+ if (panel->default_panel_size == 0)
+ panel->default_panel_size
+ = ( DisplayHeight(panel->dpy, panel->screen) > 320 ) ? 36 : 20;
+
+ panel->x = 0;
+ panel->y = 0;
+ panel->h = panel->default_panel_size;
+ panel->w = DisplayWidth(panel->dpy, panel->screen);
+
+ switch (panel->orientation)
+ {
+ case South:
+ panel->y = DisplayHeight(panel->dpy, panel->screen) - panel->h;
+ break;
+ case North:
+ break;
+ case West:
+ panel->w = panel->default_panel_size;
+ panel->h = DisplayHeight(panel->dpy, panel->screen);
+ break;
+ case East:
+ panel->w = panel->default_panel_size;
+ panel->h = DisplayHeight(panel->dpy, panel->screen);
+ panel->x = DisplayWidth(panel->dpy, panel->screen) - panel->w;
+ break;
+ }
+
+ panel->bg_pxm = None;
+
+ if ( PANEL_IS_VERTICAL(panel) )
+ panel_length = panel->h;
+ else
+ panel_length = panel->w;
+
+ /* Clip margin values to 40% */
+ if (panel->margin_start > ( ( panel_length * 40 ) / 100 )
+ || panel->margin_end > ( ( panel_length * 40 ) / 100 ))
+ {
+ fprintf(stderr, "mbdock: Panel margins too large. clipping.\n");
+ panel->margin_start = 2;
+ panel->margin_end = 2;
+ }
+
+ if (geometry_str)
+ XParseGeometry(geometry_str, &panel->x, &panel->y, &panel->w, &panel->h);
+
+ /* XXX
+ * Lots of atoms now, move to xinternatoms call ...
+ */
+ panel->atoms[0] = XInternAtom(panel->dpy, "_NET_WM_WINDOW_TYPE" ,False);
+
+ panel->atoms[1] = XInternAtom(panel->dpy, "_NET_WM_WINDOW_TYPE_DOCK",False);
+
+
+ panel->atoms[3] = XInternAtom(panel->dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
+ panel->atoms[4] = XInternAtom(panel->dpy, "_XEMBED_INFO", False);
+ panel->atoms[5] = XInternAtom(panel->dpy, "_XEMBED", False);
+ panel->atoms[6] = XInternAtom(panel->dpy, "MANAGER", False);
+
+ panel->atoms[7] = XInternAtom(panel->dpy, "_MB_DOCK_ALIGN", False);
+ panel->atoms[8] = XInternAtom(panel->dpy, "_MB_DOCK_ALIGN_EAST", False);
+
+ panel->atoms[9] = XInternAtom(panel->dpy, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
+ panel->atoms[10] = XInternAtom(panel->dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
+
+ panel->atoms[11] = XInternAtom(panel->dpy, "WM_PROTOCOLS", False);
+ panel->atoms[12] = XInternAtom(panel->dpy, "WM_DELETE_WINDOW", False);
+
+ panel->atoms[13] = XInternAtom(panel->dpy, "_MB_THEME", False);
+
+ panel->atoms[14] = XInternAtom(panel->dpy, "_MB_PANEL_TIMESTAMP", False);
+
+ panel->atoms[15] = XInternAtom(panel->dpy, "_NET_WM_STRUT", False);
+
+ panel->atoms[16] = XInternAtom(panel->dpy, "_MB_PANEL_BG", False);
+
+ panel->atoms[17] = XInternAtom(panel->dpy, "WM_CLIENT_LEADER", False);
+
+ panel->atoms[18] = XInternAtom(panel->dpy, "_NET_WM_ICON", False);
+
+ panel->atoms[ATOM_NET_WM_PID]
+ = XInternAtom(panel->dpy, "_NET_WM_PID", False);
+
+ panel->atoms[ATOM_XROOTPMAP_ID]
+ = XInternAtom(panel->dpy, "_XROOTPMAP_ID", False);
+
+ panel->atoms[ATOM_NET_SYSTEM_TRAY_ORIENTATION]
+ = XInternAtom(panel->dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
+
+ panel->atoms[ATOM_MB_THEME_NAME]
+ = XInternAtom(panel->dpy, "_MB_THEME_NAME", False);
+
+ panel->atoms[ATOM_MB_COMMAND]
+ = XInternAtom(panel->dpy, "_MB_COMMAND", False);
+
+ panel->atoms[ATOM_NET_WM_NAME]
+ = XInternAtom(panel->dpy, "_NET_WM_NAME", False);
+
+ panel->atoms[ATOM_UTF8_STRING]
+ = XInternAtom(panel->dpy, "UTF8_STRING", False);
+
+ panel->atoms[ATOM_NET_CLIENT_LIST]
+ = XInternAtom(panel->dpy, "_NET_CLIENT_LIST", False);
+
+ panel->atoms[ATOM_NET_WM_STATE]
+ = XInternAtom(panel->dpy, "_NET_WM_STATE", False);
+
+ panel->atoms[ATOM_NET_WM_STATE_TITLEBAR]
+ = XInternAtom(panel->dpy, "_MB_WM_STATE_DOCK_TITLEBAR", False);
+
+ panel->atoms[ATOM_MB_SYSTEM_TRAY_CONTEXT]
+ = XInternAtom(panel->dpy, "_MB_SYSTEM_TRAY_CONTEXT", False);
+
+ panel->atoms[ATOM_MB_REQ_CLIENT_ORDER]
+ = XInternAtom(panel->dpy, "_MB_REQ_CLIENT_ORDER", False);
+
+
+ /* Set selection atom */
+ snprintf(tray_atom_spec, 128,"_NET_SYSTEM_TRAY_S%i", panel->system_tray_id);
+
+ panel->atoms[ATOM_SYSTEM_TRAY]
+ = XInternAtom(panel->dpy, tray_atom_spec, False);
+
+ snprintf(tray_id_env_str, 16, "%i", panel->system_tray_id);
+ setenv("SYSTEM_TRAY_ID", tray_id_env_str, 1);
+
+ snprintf(win_name, 64, "Panel %i", panel->system_tray_id);
+
+ panel->pb = mb_pixbuf_new(panel->dpy, panel->screen);
+
+ gv.graphics_exposures = False;
+ gv.function = GXcopy;
+ gv.foreground = WhitePixel(panel->dpy, panel->screen);
+
+ panel->gc = XCreateGC(panel->dpy, panel->win_root,
+ GCGraphicsExposures|GCFunction|GCForeground, &gv);
+
+ dattr.background_pixel = panel->xcol.pixel;
+
+ if (geometry_str)
+ {
+ /* Make the window overide redirect - kind of evil hack for now */
+ dattr_flags = CWBackPixel|CWOverrideRedirect;
+ dattr.override_redirect = True;
+ }
+
+ panel->win = XCreateWindow(panel->dpy, panel->win_root,
+ panel->x, panel->y,
+ panel->w, panel->h,
+ panel_border_sz,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ dattr_flags,
+ &dattr);
+
+ size_hints.flags = PPosition | PSize | PMinSize;
+ size_hints.x = panel->x;
+ size_hints.y = panel->y;
+ size_hints.width = panel->w;
+ size_hints.height = panel->h;
+ size_hints.min_width = panel->w;
+ size_hints.min_height = panel->h;
+
+ XSetStandardProperties(panel->dpy, panel->win, win_name,
+ win_name, 0, argv, argc, &size_hints);
+
+ /*
+ XXX For now the menu popup button is removed.
+ If goes down well, need to rip old code out.
+
+ panel_menu_button_create(panel);
+
+ */
+
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_WM_WINDOW_TYPE], XA_ATOM, 32,
+ PropModeReplace,
+ (unsigned char *) &panel->atoms[ATOM_WM_WINDOW_TYPE_DOCK],
+ 1);
+
+ if (panel->want_titlebar_dest)
+ {
+ panel->use_flip = False;
+
+ XChangeProperty(panel->dpy, panel->win,
+ panel->atoms[ATOM_NET_WM_STATE], XA_ATOM, 32,
+ PropModeReplace,
+ (unsigned char *) &panel->atoms[ATOM_NET_WM_STATE_TITLEBAR], 1);
+
+ panel->orientation = North;
+ }
+
+ /* Set our ewmh reserved space XXX reset this when we hide */
+ wm_struct_vals[0] = ( panel->orientation == West ) ? panel->w : 0;
+ wm_struct_vals[1] = ( panel->orientation == East ) ? panel->w : 0;
+ wm_struct_vals[2] = ( panel->orientation == North ) ? panel->h : 0;
+ wm_struct_vals[3] = ( panel->orientation == South ) ? panel->h : 0;
+
+ XChangeProperty(panel->dpy, panel->win, panel->atoms[ATOM_NET_WM_STRUT],
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)wm_struct_vals, 4);
+
+ panel->msg_queue_start = NULL;
+ panel->msg_queue_end = NULL;
+ panel->msg_win = None;
+
+ panel->msg_col
+ = mb_col_new_from_spec(panel->pb, DEFAULT_MSG_BGCOL);
+ panel->msg_urgent_col
+ = mb_col_new_from_spec(panel->pb, DEFAULT_MSG_BGURGCOL);
+ panel->msg_fg_col
+ = mb_col_new_from_spec(panel->pb, DEFAULT_MSG_FGCOL);
+ panel->msg_link_col
+ = mb_col_new_from_spec(panel->pb, "blue");
+
+ panel->msg_gc = XCreateGC(panel->dpy, panel->win_root,
+ GCGraphicsExposures|GCFunction|GCForeground, &gv);
+
+ panel->msg_font = mb_font_new_from_string(panel->dpy, MB_MSG_FONT);
+
+ panel->next_click_is_not_double = True;
+ panel->is_hidden = False;
+
+ XSetWMProtocols(panel->dpy, panel->win , &panel->atoms[11], 2);
+
+ panel->mbmenu = NULL;
+ panel_menu_init(panel);
+
+ G_panel = panel; /* global for sig handlers :( */
+ panel->reload_pending = False;
+
+ util_install_signal_handlers();
+
+ /* Set the theme etc */
+
+ panel->use_themes = True;
+
+ if (color_def != NULL)
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR, color_def);
+ mb_menu_set_col(panel->mbmenu, MBMENU_SET_BG_COL, color_def);
+ panel->use_themes = False;
+ }
+ else if (bg_pixmap_def)
+ {
+ panel_set_bg(panel, BG_PIXMAP, bg_pixmap_def);
+ panel->use_themes = False;
+ }
+ else if (want_trans)
+ {
+ panel->bg_trans = strdup(want_trans);
+
+ panel_set_bg(panel, BG_TRANS, want_trans );
+ panel->use_themes = False;
+ }
+ else
+ {
+ if (!panel_set_theme_from_root_prop(panel))
+ {
+ panel_set_bg(panel, BG_SOLID_COLOR, DEFAULT_COLOR_SPEC );
+ mb_menu_set_col(panel->mbmenu, MBMENU_SET_BG_COL, DEFAULT_COLOR_SPEC );
+ }
+ }
+
+ panel->click_x = 0;
+ panel->click_y = 0;
+
+#ifdef USE_XSETTINGS
+
+ /* This will trigger callbacks instantly so called last */
+
+ panel->xsettings_client = xsettings_client_new(panel->dpy, panel->screen,
+ panel_xsettings_notify_cb,
+ NULL,
+ (void *)panel );
+#endif
+
+
+ /* Below line is there to get the menu btton on the right side */
+ panel->session_preexisting_lock = True;
+
+ return panel;
+}
+
+int main(int argc, char *argv[])
+{
+ MBPanel *panel;
+
+#if ENABLE_NLS
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, DATADIR "/locale");
+ bind_textdomain_codeset (PACKAGE, "UTF-8");
+ textdomain (PACKAGE);
+#endif
+
+ panel = panel_init(argc, argv);
+
+ /* Attempt to own the system tray selection */
+ if (!XGetSelectionOwner(panel->dpy, panel->atoms[ATOM_SYSTEM_TRAY]))
+ {
+ XSetSelectionOwner(panel->dpy, panel->atoms[ATOM_SYSTEM_TRAY],
+ panel->win, CurrentTime);
+ } else {
+ fprintf(stderr, "Panel already exists. aborting. Try running mbdock with the --id switch.\n");
+ exit(0);
+ }
+
+ /* Announce to any clients that are interested that we have it */
+ panel_send_manage_message( panel );
+
+ panel_orientation_set_hint (panel);
+
+ XMapWindow (panel->dpy, panel->win);
+
+ session_init (panel);
+
+ panel_main(panel);
+
+ return 0;
+}
+
diff --git a/src/panel.h b/src/panel.h
new file mode 100644
index 0000000..79da505
--- /dev/null
+++ b/src/panel.h
@@ -0,0 +1,312 @@
+#ifndef _DOCK_H_
+#define _DOCK_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/xpm.h>
+#include <X11/Xmd.h>
+#include <X11/extensions/shape.h>
+#include <X11/cursorfont.h>
+
+#include <libmb/mb.h>
+
+#ifdef USE_XSETTINGS
+#include <xsettings-client.h>
+#endif
+
+#define NEW(OBJ) ((OBJ *)(malloc(sizeof(OBJ))))
+
+#ifdef DEBUG
+#define DBG(txt, args... ) fprintf(stderr, "MB-PANEL-DEBUG: " txt , ##args )
+#else
+#define DBG(txt, args... ) /* nothing */
+#endif
+
+#define SWAP(a,b) { \
+ (a)^=(b); \
+ (b)^=(a); \
+ (a)^=(b); \
+ }
+
+#define PANEL_IS_VERTICAL(p) ((p)->orientation == East || (p)->orientation == West)
+
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define SYSTEM_TRAY_BEGIN_MESSAGE 1
+#define SYSTEM_TRAY_CANCEL_MESSAGE 2
+
+#define ATOM_WM_WINDOW_TYPE 0
+#define ATOM_WM_WINDOW_TYPE_DOCK 1
+#define ATOM_WM_WINDOW_TYPE_SPLASH 10
+#define ATOM_SYSTEM_TRAY 2
+#define ATOM_SYSTEM_TRAY_OPCODE 3
+#define ATOM_XEMBED_INFO 4
+#define ATOM_XEMBED_MESSAGE 5
+#define ATOM_MANAGER 6
+#define ATOM_MB_DOCK_ALIGN 7
+#define ATOM_MB_DOCK_ALIGN_EAST 8
+
+#define ATOM_NET_SYSTEM_TRAY_MESSAGE_DATA 9
+
+#define ATOM_WM_PROTOCOLS 11
+#define ATOM_WM_DELETE_WINDOW 12
+
+#define ATOM_MB_THEME 13
+#define ATOM_MB_PANEL_BG 16
+#define ATOM_MB_DOCK_TIMESTAMP 14
+#define ATOM_NET_WM_STRUT 15
+#define ATOM_WM_CLIENT_LEADER 17
+#define ATOM_NET_WM_ICON 18
+#define ATOM_NET_WM_PID 19
+#define ATOM_XROOTPMAP_ID 20
+#define ATOM_NET_SYSTEM_TRAY_ORIENTATION 21
+#define ATOM_MB_THEME_NAME 22
+#define ATOM_MB_COMMAND 23
+#define ATOM_NET_WM_NAME 24
+#define ATOM_UTF8_STRING 25
+#define ATOM_NET_CLIENT_LIST 26
+
+#define ATOM_NET_WM_STATE 27
+#define ATOM_NET_WM_STATE_TITLEBAR 28
+
+#define ATOM_MB_SYSTEM_TRAY_CONTEXT 29
+#define ATOM_MB_REQ_CLIENT_ORDER 30
+
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+
+/* ID's for various MB COMMAND X Messages */
+
+#define MB_CMD_PANEL_TOGGLE_VISIBILITY 1
+#define MB_CMD_PANEL_SIZE 2
+#define MB_CMD_PANEL_ORIENTATION 3
+
+#define MB_PANEL_ORIENTATION_NORTH 1
+#define MB_PANEL_ORIENTATION_EAST 2
+#define MB_PANEL_ORIENTATION_SOUTH 3
+#define MB_PANEL_ORIENTATION_WEST 4
+
+
+#define SESSION_TIMEOUT 10 /* 5 second session timeout */
+
+#define DBL_CLICK_TIME 200
+
+
+#define DEFAULT_COLOR_SPEC "#e2e2de" /* Same as gnome ? */
+#define MB_MSG_FONT "Sans-8:bold"
+
+enum {
+ BG_SOLID_COLOR,
+ BG_PIXMAP,
+ BG_TRANS
+};
+
+typedef enum {
+ PAPP_GRAVITY_START,
+ PAPP_GRAVITY_END,
+} PanelAppGravity;
+
+typedef enum {
+ North = 1,
+ East,
+ South,
+ West
+} MBPanelOrientation;
+
+
+typedef struct _panel_app {
+
+ Window win;
+ unsigned char *name;
+ int x;
+ int y;
+ int w;
+ int h;
+
+ int offset;
+
+ Bool mapped;
+
+ struct _panel_app *next;
+
+ char *cmd_str;
+
+ struct _panel *panel;
+
+ Bool ignore; /* set so client cant be removed */
+ int ignore_unmap;
+
+ PanelAppGravity gravity;
+
+ MBPixbufImage *icon;
+
+} MBPanelApp;
+
+typedef struct _message_queue {
+
+ MBPanelApp *sender;
+ unsigned long starttime;
+ int timeout;
+ int total_msg_length;
+ int current_msg_length;
+ int id;
+ unsigned char *data;
+
+ Bool has_extra_context;
+ unsigned char *extra_context_data;
+
+ Bool pending; /* Set to true if all data */
+
+ struct _message_queue *next;
+
+} MBPanelMessageQueue;
+
+
+typedef struct _panel {
+
+ /* General */
+
+ Display *dpy;
+ int screen;
+ MBPixbuf *pb;
+ Window win, win_root;
+ GC gc, band_gc;
+ XColor xcol;
+
+ int x,y,w,h;
+
+ MBPanelApp *apps_start_head;
+ MBPanelApp *apps_end_head;
+
+ Atom atoms[31];
+ int padding;
+ int margin_start;
+ int margin_end;
+
+ /* Message windows */
+
+ struct _message_queue *msg_queue_start;
+ struct _message_queue *msg_queue_end;
+
+ Window msg_win;
+ unsigned long msg_starttime;
+ int msg_timeout;
+ MBPanelApp *msg_win_sender;
+ Bool msg_has_context;
+ int msg_context_y1, msg_context_y2;
+
+ GC msg_gc;
+
+ MBColor *msg_col;
+ MBColor *msg_urgent_col;
+ MBColor *msg_fg_col;
+ MBColor *msg_link_col;
+
+ MBFont *msg_font;
+
+
+ /* Various state bits */
+
+ Bool use_flip;
+ Bool use_session;
+ Bool use_alt_session_defaults;
+
+ Bool use_overide_wins;
+ Bool reload_pending;
+
+ MBPanelOrientation orientation;
+
+ int system_tray_id;
+
+ Bool use_themes;
+ char *theme_name;
+ char *theme_path;
+
+ Bool want_titlebar_dest;
+
+ Bool ignore_next_config;
+
+ int default_panel_size;
+
+ /* Session */
+
+ Bool session_preexisting_lock;
+ int session_init_offset;
+ char session_entry_cur[512];
+ pid_t session_needed_pid;
+ time_t session_start_time;
+ FILE *session_fp;
+ PanelAppGravity session_cur_gravity;
+ Bool session_run_first_time;
+ char *session_defaults_cur_pos;
+
+ Window last_click_window;
+ Time last_click_time;
+ Bool next_click_is_not_double;
+ Bool is_hidden;
+
+ /* Background */
+
+ XColor bg_col;
+ Pixmap bg_tile;
+ Pixmap bg_pxm;
+ char *bg_spec;
+ int bg_type;
+
+ /* Popup menu */
+
+ MBMenu* mbmenu;
+ Bool use_menu;
+ MBMenuMenu *remove_menu;
+
+ /* co-ords of where mouse click happened for menu */
+ int click_x;
+ int click_y;
+ Time click_time;
+
+
+ char *bg_trans;
+ long root_pixmap_id;
+
+#ifdef USE_XSETTINGS
+ XSettingsClient *xsettings_client;
+#endif
+
+} MBPanel;
+
+void
+panel_handle_full_panel (MBPanel *panel, MBPanelApp *bad_papp);
+
+void
+panel_toggle_visibilty(MBPanel *panel);
+
+void
+panel_change_orientation (MBPanel *panel,
+ MBPanelOrientation new_orientation,
+ int dpy_w,
+ int dpy_h);
+
+void
+panel_update_client_list_prop (MBPanel *panel);
+
+void
+panel_reorder_apps(MBPanel *panel);
+
+#include "panel_menu.h"
+#include "panel_util.h"
+#include "panel_app.h"
+#include "session.h"
+
+#endif
diff --git a/src/panel_app.c b/src/panel_app.c
new file mode 100644
index 0000000..a3d020b
--- /dev/null
+++ b/src/panel_app.c
@@ -0,0 +1,597 @@
+#include "panel_app.h"
+
+MBPanelApp*
+panel_app_list_get_prev (MBPanel *panel,
+ MBPanelApp *papp,
+ MBPanelApp **list_head)
+{
+ MBPanelApp *tmp = *list_head;
+
+ if (tmp == NULL || papp == tmp) return NULL;
+
+ while (tmp->next != NULL)
+ {
+ if (tmp->next == papp) return tmp;
+ tmp = tmp->next;
+ }
+
+ return NULL;
+}
+
+MBPanelApp*
+panel_app_list_get_last (MBPanel *panel,
+ MBPanelApp *list_head)
+{
+ MBPanelApp *tmp = list_head;
+
+ if (tmp == NULL) return NULL;
+
+ while (tmp->next != NULL) tmp = tmp->next;
+
+ return tmp;
+}
+
+MBPanelApp*
+panel_app_list_prepend(MBPanel *panel,
+ MBPanelApp *list_to_append_to,
+ MBPanelApp *papp_new)
+{
+ papp_new->next = list_to_append_to;
+ return papp_new;
+}
+
+void
+panel_app_list_append (MBPanel *panel,
+ MBPanelApp **list_to_append_to,
+ MBPanelApp *new_client)
+{
+ MBPanelApp *tmp = NULL;
+ if (*list_to_append_to == NULL)
+ {
+ *list_to_append_to = new_client;
+ }
+ else
+ {
+ tmp = *list_to_append_to;
+ while ( tmp->next != NULL ) tmp = tmp->next;
+ tmp->next = new_client;
+ }
+
+ new_client->next = NULL;
+}
+
+void /* XXX Can probably go */
+panel_app_list_insert_after(MBPanel *panel,
+ MBPanelApp *papp,
+ MBPanelApp *new_papp)
+{
+ MBPanelApp *tmp;
+ tmp = papp->next;
+ papp->next = new_papp;
+ new_papp->next = tmp;
+}
+
+void
+panel_app_list_remove (MBPanel *panel,
+ MBPanelApp *papp,
+ MBPanelApp **list_head)
+{
+ MBPanelApp *prev_papp = panel_app_list_get_prev(panel, papp, list_head);
+
+ if (prev_papp == NULL)
+ {
+ *list_head = papp->next;
+ }
+ else
+ {
+ prev_papp->next = papp->next;
+ }
+ return;
+}
+
+void
+panel_app_name_get(MBPanel *panel,
+ MBPanelApp *papp)
+{
+ Atom type;
+ int format;
+ long bytes_after;
+ long n_items;
+ int result;
+
+ result = XGetWindowProperty (panel->dpy, papp->win,
+ panel->atoms[ATOM_NET_WM_NAME],
+ 0, 1024L,
+ False, panel->atoms[ATOM_UTF8_STRING],
+ &type, &format, &n_items,
+ &bytes_after, (unsigned char **)&papp->name);
+
+ if (result != Success
+ || papp->name == NULL
+ || type != panel->atoms[ATOM_UTF8_STRING]
+ || format != 8
+ || n_items == 0)
+ {
+ if (papp->name) XFree (papp->name);
+
+ XFetchName(panel->dpy, papp->win, (char **)&papp->name);
+ if (papp->name == NULL) {
+ XStoreName(panel->dpy, papp->win, "<unnamed>");
+ XFetchName(panel->dpy, papp->win, (char **)&papp->name);
+ if (papp->name == NULL)
+ papp->name = strdup("<unnamed>");
+ }
+ }
+}
+
+Window
+panel_app_get_client_leader_win(MBPanel *panel, MBPanelApp *papp)
+{
+ Atom realType;
+ unsigned long n;
+ unsigned long extra;
+ int format;
+ int status;
+ Window* value = NULL, win_result = None;
+
+ status = XGetWindowProperty(panel->dpy, papp->win,
+ panel->atoms[ATOM_WM_CLIENT_LEADER],
+ 0L, 16L,
+ 0, XA_WINDOW, &realType, &format,
+ &n, &extra, (unsigned char **) &value);
+ if (status == Success && realType == XA_WINDOW
+ && format == 32 && n == 1 && value != NULL)
+ {
+ win_result = (Window) value[0];
+ }
+
+ if (value) XFree(value);
+
+ return win_result;
+}
+
+int*
+panel_app_icon_prop_data_get(MBPanel *d, MBPanelApp *papp)
+{
+ Atom type;
+ int format;
+ long bytes_after;
+ unsigned char *data = NULL;
+ long n_items;
+ int result;
+
+ result = XGetWindowProperty (d->dpy, papp->win,
+ d->atoms[ATOM_NET_WM_ICON],
+ 0, 100000L,
+ False, XA_CARDINAL,
+ &type, &format, &n_items,
+ &bytes_after, (unsigned char **)&data);
+
+ if (result != Success || data == NULL)
+ {
+ if (data) XFree (data);
+ DBG("%s() failed for %s (XID: %li)\n", __func__, papp->name, papp->win);
+ return NULL;
+ }
+
+ return (int *)data;
+}
+
+void
+panel_app_add_start(MBPanel *panel, MBPanelApp *papp_new)
+{
+ MBPanelApp *papp_prev;
+
+ papp_prev = panel_app_list_get_last(panel, panel->apps_start_head);
+
+ panel_app_list_append (panel, &panel->apps_start_head, papp_new);
+
+ if (papp_prev != NULL)
+ {
+ papp_new->offset = panel_app_get_offset(panel, papp_prev)
+ + panel_app_get_size(panel, papp_prev);
+ DBG("%s() got %i = %i + %i\n", __func__, papp_new->offset,
+ panel_app_get_offset(panel, papp_prev) ,
+ panel_app_get_size(panel, papp_prev) );
+ }
+ else
+ papp_new->offset = 0;
+
+ papp_new->gravity = PAPP_GRAVITY_START;
+}
+
+void
+panel_app_add_end(MBPanel *panel, MBPanelApp *papp_new)
+{
+ MBPanelApp *papp_prev;
+
+ papp_prev = panel_app_list_get_last(panel, panel->apps_end_head);
+
+ panel_app_list_append (panel, &panel->apps_end_head, papp_new);
+
+ if (papp_prev != NULL)
+ papp_new->offset = panel_app_get_offset(panel, papp_prev)
+ - panel_app_get_size(panel, papp_new);
+ else
+ papp_new->offset = ( PANEL_IS_VERTICAL(panel) ? panel->h : panel->w )
+ - panel_app_get_size(panel, papp_new);
+
+ papp_new->gravity = PAPP_GRAVITY_END;
+}
+
+Bool
+panel_app_check_for_space (MBPanel *panel, MBPanelApp *papp)
+{
+ MBPanelApp *papp_end = NULL, *papp_start = NULL;
+
+ papp_end = panel_app_list_get_last(panel, panel->apps_end_head);
+ papp_start = panel_app_list_get_last(panel, panel->apps_start_head);
+
+ if (papp_end && papp_start &&
+ panel_app_get_offset(panel, papp_start)
+ + panel_app_get_size(panel, papp_start)
+ > panel_app_get_offset(panel, papp_end))
+ {
+ panel_handle_full_panel(panel, papp);
+ return False;
+ }
+ return True;
+}
+
+MBPanelApp *
+panel_app_new(MBPanel *panel, Window win, char *cmd_str)
+{
+ MBPanelApp *papp;
+ XWindowAttributes attr;
+ int padding = 0;
+ Bool add_at_start = False;
+
+ papp = NEW(MBPanelApp);
+
+ papp->next = NULL;
+ papp->win = win;
+ papp->panel = panel;
+ papp->ignore = False;
+ papp->ignore_unmap = 0;
+ papp->icon = NULL;
+
+ /* XXX should check we actually get this */
+ XGetWindowAttributes(panel->dpy, win, &attr);
+
+ papp->w = attr.width;
+ papp->h = attr.height;
+
+ if (session_preexisting_restarting(panel) && !panel->session_run_first_time)
+ {
+ if (panel->session_cur_gravity == PAPP_GRAVITY_START)
+ add_at_start = True;
+ }
+ else if ( ((attr.x < 0) && !PANEL_IS_VERTICAL(panel))
+ || ((attr.y < 0) && PANEL_IS_VERTICAL(panel)))
+ {
+ add_at_start = True;
+ }
+
+ if (add_at_start)
+ {
+ if (panel->apps_start_head == NULL)
+ padding = panel->margin_start;
+ else
+ padding = panel->padding;
+
+ panel_app_add_start(panel, papp);
+ }
+ else
+ {
+ if (panel->apps_end_head == NULL)
+ padding = -1 * panel->margin_end;
+ else
+ padding = -1 * panel->padding;
+
+ panel_app_add_end(panel, papp);
+ }
+
+ DBG("%s() papp offset at %i\n", __func__, papp->offset );
+
+ panel_app_name_get(panel, papp);
+
+ papp->cmd_str = cmd_str;
+
+ if (panel->orientation == North || panel->orientation == South)
+ {
+ papp->h = panel->h - 4;
+ papp->y = (panel->h - papp->h) / 2;
+ papp->x = papp->offset + padding;
+ }
+ else
+ {
+ papp->w = panel->w - 4;
+ papp->x = (panel->w - papp->w) / 2;
+ papp->y = papp->offset + padding;
+ }
+
+ if (!panel_app_check_for_space(panel, papp))
+ return NULL;
+
+ XResizeWindow(panel->dpy, papp->win, papp->w, papp->h);
+ XReparentWindow(panel->dpy, papp->win, panel->win, papp->x, papp->y);
+ panel_app_deliver_config_event(panel, papp);
+
+ panel_update_client_list_prop (panel);
+
+ return papp;
+}
+
+void
+panel_app_handle_configure_request(MBPanel *panel, XConfigureRequestEvent *ev)
+{
+ XWindowChanges xwc;
+ MBPanelApp *papp = NULL;
+
+ papp = panel_app_get_from_window( panel, ev->window );
+
+ if (panel->is_hidden) return;
+
+ if (papp != NULL)
+ {
+ DBG("%s() config req x: %i , y: %i w: %i h: %i for %s\n",
+ __func__, ev->x, ev->y, ev->width, ev->height, papp->name );
+
+ DBG("%s() panel is w: %i %i h:\n",
+ __func__, panel->w, panel->h );
+
+ if (panel->orientation == North || panel->orientation == South)
+ {
+ xwc.width = ev->width;
+ xwc.height = panel->h - 4;
+
+ papp->y = (panel->h - papp->h) / 2;
+
+ if (xwc.width != papp->w) /* Handle width changes */
+ {
+ if (papp == panel_app_list_get_last(panel, panel->apps_end_head))
+ {
+ panel_app_move_to(panel, papp,
+ papp->x - (xwc.width - papp->w));
+ }
+ else if (papp == panel_app_list_get_last(panel,
+ panel->apps_start_head))
+ {
+ panel_app_move_to(panel, papp,
+ papp->x + (xwc.width - papp->w));
+ }
+ else
+ {
+ panel_apps_nudge (panel, papp->next, xwc.width - papp->w);
+ }
+ papp->w = xwc.width;
+ }
+
+ xwc.x = papp->x; /* NOT allowed to move themselves */
+ xwc.y = papp->y;
+
+ } else { /* East / West orientated dock */
+
+ xwc.width = panel->w - 4;
+ xwc.height = ev->height;
+
+ papp->x = (panel->w - papp->w) / 2;
+ xwc.x = papp->x;
+ xwc.y = papp->y;
+
+ if (xwc.height != papp->h) /* Handle width changes */
+ {
+ if (papp == panel_app_list_get_last(panel, panel->apps_end_head))
+ {
+ panel_app_move_to(panel, papp,
+ papp->y - (xwc.height - papp->h));
+ }
+ else if (papp == panel_app_list_get_last(panel,
+ panel->apps_start_head))
+ {
+ panel_app_move_to(panel, papp,
+ papp->y + (xwc.height - papp->h));
+ }
+ else
+ {
+ panel_apps_nudge (panel, papp->next, xwc.height - papp->h);
+ }
+ papp->h = xwc.height;
+ }
+ }
+
+ xwc.border_width = 0;
+ xwc.sibling = None;
+ xwc.stack_mode = None;
+
+ DBG("%s() setting x: %i , y: %i w: %i h: %i \n",
+ __func__, xwc.x, xwc.y, xwc.width, xwc.height );
+
+ XConfigureWindow(panel->dpy, papp->win, ev->value_mask, &xwc);
+ }
+}
+
+void
+panel_app_deliver_config_event(MBPanel *panel, MBPanelApp *papp)
+{
+ XConfigureEvent ce;
+
+ if (panel->is_hidden) return;
+
+ ce.type = ConfigureNotify;
+ ce.event = papp->win;
+ ce.window = papp->win;
+
+ if (PANEL_IS_VERTICAL(panel))
+ {
+ papp->x = (panel->w - papp->w) / 2;
+ ce.x = papp->x;
+ ce.y = papp->y;
+ ce.width = papp->w;
+ ce.height = papp->h;
+ } else {
+ papp->y = (panel->h - papp->h) / 2;
+ ce.x = papp->x;
+ ce.y = papp->y; // + panel->y;
+ ce.width = papp->w;
+ ce.height = papp->h;
+ }
+
+ ce.border_width = 0;
+ ce.above = panel->win;
+ ce.override_redirect = 0;
+
+ DBG("%s() delivering x: %i , y: %i w: %i h: %i name : %s\n",
+ __func__, ce.x, ce.y, ce.width, ce.height, papp->name );
+
+ XSendEvent(panel->dpy, papp->win, False,
+ StructureNotifyMask, (XEvent *)&ce);
+}
+
+void
+panel_app_move_to (MBPanel *panel,
+ MBPanelApp *papp,
+ int origin_offset)
+{
+ if (panel->orientation == North || panel->orientation == South)
+ {
+ papp->x = origin_offset;
+ papp->y = (panel->h - papp->h) / 2;
+ }
+ else
+ {
+ papp->y = origin_offset;
+ papp->x = (panel->w - papp->w) / 2;
+ }
+
+ papp->offset = origin_offset;
+
+ if (!panel_app_check_for_space(panel, papp))
+ return;
+
+ XMoveWindow(panel->dpy, papp->win, papp->x, papp->y);
+}
+
+void
+panel_apps_nudge (MBPanel *panel,
+ MBPanelApp *papp,
+ int amount)
+{
+ MBPanelApp *papp_cur = papp;
+
+ while (papp_cur != NULL)
+ {
+ panel_app_move_to (panel, papp_cur,
+ panel_app_get_offset(panel, papp_cur) + amount);
+ papp_cur = papp_cur->next;
+ }
+}
+
+void
+panel_apps_rescale (MBPanel *panel,
+ MBPanelApp *papp)
+{
+ MBPanelApp *papp_cur = papp;
+
+ while (papp_cur != NULL)
+ {
+ papp->h = panel->h - 4;
+ XResizeWindow(panel->dpy, papp->win, papp->w, papp->h);
+ panel_app_deliver_config_event(panel, papp);
+ papp_cur = papp_cur->next;
+ }
+}
+
+void
+panel_app_destroy (MBPanel *panel,
+ MBPanelApp *papp)
+{
+ MBMenuItem *tmp = NULL;
+
+ if (!papp) return;
+
+ /* remove popup menu entry XXX this functionaility should be in mbmenu */
+ if (panel->remove_menu)
+ tmp = panel->remove_menu->items;
+
+ while (tmp != NULL)
+ {
+ if ((MBPanelApp *)tmp->cb_data == papp)
+ {
+ mb_menu_item_remove(panel->mbmenu, panel->remove_menu, tmp);
+ break;
+ }
+ tmp = tmp->next_item;
+ }
+
+ if (papp->gravity == PAPP_GRAVITY_START)
+ {
+ panel_apps_nudge(panel, papp->next,
+ -1 * panel_app_get_size(panel, papp));
+ panel_app_list_remove(panel, papp, &panel->apps_start_head);
+ }
+ else
+ {
+ panel_apps_nudge(panel, papp->next, panel_app_get_size(panel, papp));
+ panel_app_list_remove(panel, papp, &panel->apps_end_head);
+ }
+
+ if (papp->name) XFree(papp->name);
+
+ if (papp->cmd_str) free(papp->cmd_str);
+
+ if (papp->icon) mb_pixbuf_img_free(panel->pb, papp->icon);
+
+ free(papp);
+
+ panel_update_client_list_prop (panel);
+}
+
+/* Utilities */
+
+int
+panel_app_get_offset (MBPanel *panel,
+ MBPanelApp *papp)
+{
+ if (panel->orientation == East || panel->orientation == West)
+ return papp->y;
+ else
+ return papp->x;
+}
+
+int
+panel_app_get_size (MBPanel *panel,
+ MBPanelApp *papp)
+{
+ if (panel->orientation == East || panel->orientation == West)
+ return papp->h;
+ else
+ return papp->w;
+}
+
+MBPanelApp*
+panel_app_get_from_window (MBPanel *panel,
+ Window win)
+{
+ MBPanelApp *papp = panel->apps_start_head;
+ DBG("%s() called, looking for win %li\n", __func__, win);
+
+ while( papp != NULL)
+ {
+ DBG("%s() check %s ( %li )\n", __func__, papp->name, papp->win);
+ if (papp->win == win) return papp;
+ papp = papp->next;
+ }
+
+ papp = panel->apps_end_head;
+
+ while( papp != NULL)
+ {
+ // DBG("%s() check %s ( %li )\n", __func__, papp->name, papp->win);
+ if (papp->win == win) return papp;
+ papp = papp->next;
+ }
+
+ return NULL;
+}
+
diff --git a/src/panel_app.h b/src/panel_app.h
new file mode 100644
index 0000000..cb13deb
--- /dev/null
+++ b/src/panel_app.h
@@ -0,0 +1,92 @@
+#ifndef _PANEL_APP_H_
+#define _PANEL_APP_H_
+
+#include "panel.h"
+
+MBPanelApp*
+panel_app_list_get_prev (MBPanel *panel,
+ MBPanelApp *papp,
+ MBPanelApp **list_head);
+MBPanelApp*
+panel_app_list_get_last (MBPanel *panel,
+ MBPanelApp *list_head);
+
+
+MBPanelApp *
+panel_app_list_prepend(MBPanel *panel,
+ MBPanelApp *list_to_append_to,
+ MBPanelApp *papp_new);
+
+/*
+void
+panel_app_list_prepend(MBPanel *panel,
+ MBPanelApp **list_to_append_to,
+ MBPanelApp *papp_new);
+*/
+
+void
+panel_app_list_append (MBPanel *panel,
+ MBPanelApp **list_to_append_to,
+ MBPanelApp *new_client);
+
+
+void panel_app_list_insert_after(MBPanel *panel, MBPanelApp *papp,
+ MBPanelApp *new_papp);
+
+void panel_app_list_remove (MBPanel *panel,
+ MBPanelApp *papp,
+ MBPanelApp **list_head );
+
+void
+panel_app_add_start(MBPanel *panel, MBPanelApp *papp_new);
+
+void
+panel_app_add_end(MBPanel *panel, MBPanelApp *papp_new);
+
+
+void panel_app_list_add(MBPanel *panel, MBPanelApp *papp_new);
+
+void panel_app_name_get(MBPanel *panel, MBPanelApp *papp);
+
+Window panel_app_get_client_leader_win(MBPanel *panel, MBPanelApp *papp);
+
+int* panel_app_icon_prop_data_get(MBPanel *d, MBPanelApp *papp);
+
+void panel_app_command_prop_get(MBPanel *panel, MBPanelApp *papp);
+
+Bool panel_app_get_command_str(MBPanel *panel, MBPanelApp *papp,
+ char **result);
+
+MBPanelApp* panel_app_get_from_window(MBPanel *panel, Window win);
+
+MBPanelApp* panel_app_new(MBPanel *panel,
+ Window win,
+ char *cmd );
+
+void panel_app_handle_configure_request(MBPanel *panel,
+ XConfigureRequestEvent *ev);
+
+void panel_app_deliver_config_event(MBPanel *panel, MBPanelApp *papp);
+
+void
+panel_apps_rescale (MBPanel *panel,
+ MBPanelApp *papp);
+
+void
+panel_apps_nudge (MBPanel *panel,
+ MBPanelApp *papp,
+ int amount);
+
+void
+panel_app_move_to(MBPanel *panel, MBPanelApp *papp, int origin_offset);
+
+void
+panel_app_destroy(MBPanel *panel, MBPanelApp *papp);
+
+int
+panel_app_get_offset(MBPanel *panel, MBPanelApp *papp);
+
+int
+panel_app_get_size(MBPanel *panel, MBPanelApp *papp);
+
+#endif
diff --git a/src/panel_menu.c b/src/panel_menu.c
new file mode 100644
index 0000000..fbb6169
--- /dev/null
+++ b/src/panel_menu.c
@@ -0,0 +1,276 @@
+#include "panel_menu.h"
+
+#ifdef USE_PNG
+#define FOLDER_IMG "mbfolder.png"
+#define ADD_IMG "mbadd.png"
+#define REMOVE_IMG "mbremove.png"
+#define HIDE_IMG "mbdown.png"
+#else
+#define FOLDER_IMG "mbfolder.xpm"
+#define ADD_IMG "mbadd.xpm"
+#define REMOVE_IMG "mbremove.xpm"
+#define HIDE_IMG "mbdown.xpm"
+#endif
+
+void panel_menu_exec_cb(MBMenuItem *item)
+{
+ char *cmd = strdup(item->info);
+
+ util_fork_exec(cmd);
+ free(cmd);
+}
+
+void panel_menu_exit_cb(MBMenuItem *item)
+{
+ /* This should only be called by the menu.
+ As we now delete the session file. So its not used again.
+ */
+ MBPanel *panel = (MBPanel *)item->cb_data;
+ session_destroy(panel);
+
+ util_cleanup_children(0);
+}
+
+void panel_menu_hide_cb(MBMenuItem *item)
+{
+ MBPanel *panel = (MBPanel *)item->cb_data;
+ panel_toggle_visibilty(panel);
+}
+
+void panel_menu_kill_cb(MBMenuItem *item)
+{
+ MBPanelApp *papp = (MBPanelApp *)item->cb_data;
+
+ XGrabServer(papp->panel->dpy);
+ XKillClient(papp->panel->dpy, papp->win);
+ session_save(papp->panel);
+ XUngrabServer(papp->panel->dpy);
+}
+
+void
+panel_menu_update_remove_items(MBPanel *panel)
+{
+ int *icon_data = NULL;
+ MBMenuItem *menu_item;
+ MBPanelApp *papp = NULL;
+ MBPanelApp *papp_heads[] = { panel->apps_start_head,
+ panel->apps_end_head,
+ NULL };
+ int i = 0;
+
+ if (panel->remove_menu == NULL)
+ {
+ char *icon_path = NULL;
+
+ icon_path = mb_dot_desktop_icon_get_full_path (panel->theme_name,
+ 16, REMOVE_IMG );
+
+ panel->remove_menu = mb_menu_add_path(panel->mbmenu, _("Remove"),
+ icon_path,
+ MBMENU_PREPEND);
+ if (icon_path) free(icon_path);
+ }
+
+ /* Remove all items then readd so order matches panel */
+
+ if (panel->remove_menu->items)
+ {
+ MBMenuItem *tmp_item = NULL;
+
+ menu_item = panel->remove_menu->items;
+
+ while (menu_item != NULL)
+ {
+ tmp_item = menu_item->next_item;
+ mb_menu_item_remove(panel->mbmenu, panel->remove_menu, menu_item);
+ menu_item = tmp_item;
+ }
+ }
+
+
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+
+ if (i == 1)
+ papp = panel_app_list_get_last(panel, panel->apps_end_head);
+
+ while( papp != NULL)
+ {
+ if (!papp->ignore)
+ {
+ menu_item = mb_menu_add_item_to_menu(panel->mbmenu,
+ panel->remove_menu,
+ papp->name, NULL,
+ papp->name,
+ panel_menu_kill_cb,
+ (void *)papp,
+ MBMENU_NO_SORT);
+
+ if (!papp->icon)
+ {
+ if ((icon_data = panel_app_icon_prop_data_get(panel, papp))
+ != NULL )
+ {
+ char *p;
+ int j;
+
+ DBG("%s() Got icon data (size: %i x %i)\n", __func__,
+ icon_data[0], icon_data[1] );
+
+ papp->icon = mb_pixbuf_img_new(panel->pb,
+ icon_data[0], icon_data[1] );
+ p = papp->icon->rgba;
+
+ for (j =0 ; j < (icon_data[0]*icon_data[1]); j++)
+ {
+ *p++ = (icon_data[j+2] >> 16) & 0xff;
+ *p++ = (icon_data[j+2] >> 8) & 0xff;
+ *p++ = icon_data[j+2] & 0xff;
+ *p++ = icon_data[j+2] >> 24;
+ }
+
+ XFree(icon_data);
+ }
+ }
+
+ if (papp->icon)
+ mb_menu_item_icon_set(panel->mbmenu, menu_item, papp->icon);
+ }
+
+ if (i == 1)
+ {
+ papp = panel_app_list_get_prev (panel, papp,
+ &panel->apps_end_head);
+ }
+ else papp = papp->next;
+ }
+ i++;
+ }
+
+}
+
+void
+panel_menu_init(MBPanel *panel)
+{
+ MBMenuMenu *m, *menu_launchers;
+ char orig_wd[256] = { 0 };
+ struct dirent *dir_entry;
+ char *icon_path = NULL;
+ DIR *dp;
+
+ if (panel->mbmenu == NULL)
+ {
+ panel->mbmenu = mb_menu_new(panel->dpy, panel->screen );
+ mb_menu_set_icon_size(panel->mbmenu, 16);
+ }
+ else mb_menu_free(panel->mbmenu); /* XXX should be mb_menu_empty */
+
+ icon_path = mb_dot_desktop_icon_get_full_path (panel->theme_name,
+ 16, ADD_IMG );
+
+ m = mb_menu_add_path(panel->mbmenu, _("Add"), icon_path,
+ MBMENU_NO_SORT );
+
+ if (icon_path) free(icon_path);
+
+ icon_path = mb_dot_desktop_icon_get_full_path (panel->theme_name,
+ 16, FOLDER_IMG );
+
+ menu_launchers = mb_menu_add_path(panel->mbmenu, "Add/Launchers",
+ icon_path, MBMENU_NO_SORT );
+
+ if (icon_path) free(icon_path);
+
+ if (getcwd(orig_wd, 255) == (char *)NULL)
+ {
+ printf("Cant get current directory\n");
+ exit(0);
+ }
+
+ if ((dp = opendir(DATADIR "/applications")) != NULL)
+ {
+ chdir(DATADIR "/applications");
+
+ while((dir_entry = readdir(dp)) != NULL)
+ {
+ struct stat stat_info;
+ stat(dir_entry->d_name, &stat_info);
+ if (!(stat_info.st_mode & S_IFDIR))
+ {
+ MBDotDesktop *ddentry = NULL;
+ ddentry = mb_dotdesktop_new_from_file(dir_entry->d_name);
+ if (ddentry
+ && mb_dotdesktop_get(ddentry, "Type")
+ && mb_dotdesktop_get(ddentry, "Name")
+ && mb_dotdesktop_get(ddentry, "Exec")
+ )
+ {
+
+ char *png_path = NULL;
+ unsigned char *icon_str = mb_dotdesktop_get(ddentry, "Icon");
+
+ png_path = mb_dot_desktop_icon_get_full_path (
+ panel->theme_name,
+ 16, icon_str );
+
+ if (!strcmp(mb_dotdesktop_get(ddentry, "Type"), "PanelApp"))
+ {
+ mb_menu_add_item_to_menu(panel->mbmenu,
+ m,
+ mb_dotdesktop_get(ddentry,
+ "Name"),
+ png_path,
+ mb_dotdesktop_get(ddentry,
+ "Exec"),
+ panel_menu_exec_cb,
+ (void *)panel, 0);
+ } else {
+ char launcher_exec_str[256] = { 0 };
+ snprintf(launcher_exec_str, 256,
+ "monolaunch -o -1 --desktop %s/%s",
+ DATADIR "/applications", dir_entry->d_name);
+ mb_menu_add_item_to_menu(panel->mbmenu,
+ menu_launchers,
+ mb_dotdesktop_get(ddentry,
+ "Name"),
+ png_path,
+ launcher_exec_str,
+ panel_menu_exec_cb,
+ (void *)panel, 0);
+
+ }
+ if (png_path) free(png_path);
+ mb_dotdesktop_free(ddentry);
+ }
+ }
+ }
+ closedir(dp);
+ }
+ else fprintf(stderr, "failed to open %s\n", DATADIR "/applications");
+
+ chdir(orig_wd);
+
+ panel->remove_menu = NULL;
+
+ icon_path = mb_dot_desktop_icon_get_full_path (panel->theme_name,
+ 16, HIDE_IMG );
+
+ mb_menu_add_item_to_menu(panel->mbmenu, panel->mbmenu->rootmenu, _("Hide"),
+ icon_path, NULL ,
+ panel_menu_hide_cb, (void *)panel, MBMENU_NO_SORT);
+
+
+ if (panel->system_tray_id > 0)
+ mb_menu_add_item_to_menu(panel->mbmenu, panel->mbmenu->rootmenu,
+ "Exit",
+ NULL, NULL ,
+ panel_menu_exit_cb,
+ (void *)panel, MBMENU_NO_SORT);
+
+
+ if (icon_path) free(icon_path);
+
+ return;
+}
+
diff --git a/src/panel_menu.h b/src/panel_menu.h
new file mode 100644
index 0000000..87839ab
--- /dev/null
+++ b/src/panel_menu.h
@@ -0,0 +1,27 @@
+#ifndef _HAVE_PANEL_MENU_H
+#define _HAVE_PANEL_MENU_H
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(text) gettext(text)
+#else
+# define _(text) (text)
+#endif
+
+#include "panel.h"
+
+void panel_menu_exec_cb(MBMenuItem *item);
+
+void panel_menu_exit_cb(MBMenuItem *item);
+
+void panel_menu_hide_cb(MBMenuItem *item);
+
+void panel_menu_move_app_cb(MBMenuItem *item);
+
+void panel_menu_kill_cb(MBMenuItem *item);
+
+void panel_menu_update_remove_items(MBPanel *panel);
+
+void panel_menu_init(MBPanel *panel);
+
+#endif
diff --git a/src/panel_util.c b/src/panel_util.c
new file mode 100644
index 0000000..593413f
--- /dev/null
+++ b/src/panel_util.c
@@ -0,0 +1,233 @@
+#include "panel_util.h"
+
+extern MBPanel* G_panel;
+
+void
+util_cleanup_children(int s)
+{
+ DBG("DIE DIE\n");
+ kill(-getpid(), 15); /* kill every one in our process group */
+ exit(0);
+}
+
+void
+util_install_signal_handlers(void)
+{
+
+ signal (SIGCHLD, SIG_IGN); /* kernel can deal with zombies */
+ signal (SIGINT, util_cleanup_children);
+ signal (SIGQUIT, util_cleanup_children);
+ signal (SIGTERM, util_cleanup_children);
+ signal (SIGHUP, util_handle_hup);
+ signal (SIGALRM, util_handle_alarm);
+ // signal (SIGSEGV, cleanup_children);
+
+}
+
+int
+util_handle_xerror(Display *dpy, XErrorEvent *e)
+{
+ char msg[255];
+ XGetErrorText(dpy, e->error_code, msg, sizeof msg);
+ fprintf(stderr, "Panel X error (%#lx):\n %s (opcode: %i)\n",
+ e->resourceid, msg, e->request_code);
+ return 0;
+}
+
+pid_t
+util_fork_exec(char *cmd)
+{
+ pid_t pid, mypid;
+ mypid = getpid();
+ pid = fork();
+
+ switch (pid) {
+ case 0:
+ setpgid (0, mypid); /* set pgid to parents pid */
+ mb_exec(cmd);
+ fprintf(stderr, "exec failed, cleaning up child\n");
+ exit(1);
+ case -1:
+ fprintf(stderr, "can't fork\n"); break;
+ }
+ return pid;
+}
+
+
+void
+util_handle_alarm(int s)
+{
+ MBPanel *p = G_panel;
+ DBG("%s() called", __func__);
+ session_save(p);
+}
+
+void
+util_handle_hup(int s)
+{
+ MBPanel *p = G_panel;
+ DBG("%s() called", __func__);
+
+ if (p != NULL)
+ {
+ p->reload_pending = True;
+ }
+}
+
+void
+util_get_mouse_position(MBPanel *panel, int *x, int *y)
+{
+ Window mouse_root, mouse_win;
+ int win_x, win_y;
+ unsigned int mask;
+
+ XQueryPointer(panel->dpy, panel->win_root, &mouse_root, &mouse_win,
+ x, y, &win_x, &win_y, &mask);
+}
+
+pid_t
+util_get_window_pid_from_prop(MBPanel *panel, Window win)
+{
+ Atom type;
+ int format;
+ long bytes_after;
+ unsigned int *data = NULL;
+ long n_items;
+ int result;
+ pid_t pid_result = 0;
+
+ result = XGetWindowProperty (panel->dpy, win,
+ panel->atoms[ATOM_NET_WM_PID],
+ 0, 16L,
+ False, XA_CARDINAL,
+ &type, &format, &n_items,
+ &bytes_after, (unsigned char **)&data);
+
+ if (result == Success && n_items)
+ pid_result = *data;
+
+ if (data) XFree(data);
+
+ return pid_result;
+}
+
+Bool
+util_get_command_str_from_win(MBPanel *panel, Window win, char **result)
+{
+ int i, bytes_needed = 0;
+ char *p = NULL, *cmd = NULL, **argv_win;
+ int argc_win;
+
+ if (!XGetCommand(panel->dpy, win, &argv_win, &argc_win))
+ return False;
+
+ bytes_needed = strlen(argv_win[0])+2;
+
+ for(i=1;i<argc_win;i++)
+ {
+ bytes_needed += strlen(argv_win[i])+2;
+ for (p = argv_win[i]; *p != '\0'; p++)
+ if (*p == ' ' || *p == '\t')
+ bytes_needed++;
+ }
+
+ *result = malloc(sizeof(char)*bytes_needed);
+ cmd = *result;
+
+ strcpy(cmd, argv_win[0]);
+ while(*cmd != '\0') cmd++;
+
+ for(i=1;i<argc_win;i++)
+ {
+ p = argv_win[i];
+ *cmd++ = ' ';
+
+ if (strpbrk(p, " \t") == NULL)
+ {
+ while (*p) *cmd++ = *p++;
+ } else {
+ *cmd++ = '\'';
+ while (*p)
+ {
+ if (*p == '\'')
+ *cmd++ = '\\';
+ *cmd++ = *p++;
+ }
+ *cmd++ = '\'';
+ }
+ }
+
+ *cmd = '\0';
+
+ XFreeStringList(argv_win);
+
+ return True;
+}
+
+Bool
+util_xcol_from_spec(MBPanel *panel, MBColor *col, char *spec)
+{
+ mb_col_set (col, spec);
+ return True;
+}
+
+Pixmap
+util_get_root_pixmap(MBPanel *panel)
+{
+ Pixmap root_pxm = None;
+
+ Atom type;
+ int format;
+ long bytes_after;
+ Pixmap *data = NULL;
+ long n_items;
+ int result;
+
+ result = XGetWindowProperty (panel->dpy, panel->win_root,
+ panel->atoms[ATOM_XROOTPMAP_ID],
+ 0, 16L,
+ False, XA_PIXMAP,
+ &type, &format, &n_items,
+ &bytes_after, (unsigned char **)&data);
+
+ if (result == Success && n_items)
+ root_pxm = *data;
+
+ if (data) XFree(data);
+
+ panel->root_pixmap_id = root_pxm;
+
+ return root_pxm;
+}
+
+unsigned char *
+util_get_utf8_prop(MBPanel *panel, Window win, Atom req_atom)
+{
+ Atom type;
+ int format;
+ long bytes_after;
+ unsigned char *str = NULL;
+ long n_items;
+ int result;
+
+ result = XGetWindowProperty (panel->dpy, win,
+ req_atom,
+ 0, 1024L,
+ False, panel->atoms[ATOM_UTF8_STRING],
+ &type, &format, &n_items,
+ &bytes_after, (unsigned char **)&str);
+
+ if (result != Success || str == NULL)
+ {
+ if (str) XFree (str);
+ return NULL;
+ }
+
+ if (type != panel->atoms[ATOM_UTF8_STRING] || format != 8 || n_items == 0)
+ {
+ XFree (str);
+ return NULL;
+ }
+
+ return str;
+}
diff --git a/src/panel_util.h b/src/panel_util.h
new file mode 100644
index 0000000..01a59b1
--- /dev/null
+++ b/src/panel_util.h
@@ -0,0 +1,33 @@
+#ifndef _HAVE_PANEL_UTIL_H
+#define _HAVE_PANEL_UTIL_H
+
+#include "panel.h"
+
+void util_cleanup_children(int s);
+
+void util_install_signal_handlers(void);
+
+int util_handle_xerror(Display *dpy, XErrorEvent *e);
+
+pid_t util_fork_exec(char *cmd);
+
+void util_handle_alarm(int s);
+
+void util_handle_hup(int s);
+
+void util_get_mouse_position(MBPanel *panel, int *x, int *y);
+
+pid_t util_get_window_pid_from_prop(MBPanel *panel, Window win);
+
+Bool util_get_command_str_from_win(MBPanel *panel, Window win, char **result);
+
+Bool
+util_xcol_from_spec(MBPanel *panel, MBColor *col, char *spec);
+
+Pixmap util_get_root_pixmap(MBPanel *panel);
+
+unsigned char *
+util_get_utf8_prop(MBPanel *panel, Window win, Atom req_atom);
+
+
+#endif
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 0000000..75c29ae
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,311 @@
+#include "session.h"
+
+#define DEFAULT_SESSIONS "mbmenu,minitime"
+
+void
+session_set_defaults(MBPanel *panel, char *defaults)
+{
+ panel->session_defaults_cur_pos = strdup(defaults);
+ panel->use_alt_session_defaults = True;
+}
+
+void
+session_destroy(MBPanel *panel)
+{
+ char sessionfile[512] = { 0 };
+
+ if (!panel->use_session) return;
+
+ if (panel->system_tray_id)
+ snprintf(sessionfile, 512, "%s/.matchbox/%s.%i", getenv("HOME"),
+ PANELFILE, panel->system_tray_id );
+ else
+ snprintf(sessionfile, 512, "%s/.matchbox/%s",
+ getenv("HOME"), PANELFILE );
+
+ unlink(sessionfile);
+}
+
+void
+session_init(MBPanel *panel)
+{
+ char sessionfile[512] = { 0 };
+ struct stat st;
+
+ DBG("%s() called\n", __func__);
+
+ panel->session_preexisting_lock = False;
+ panel->session_run_first_time = False;
+
+ if (!panel->use_session && !panel->use_alt_session_defaults) return;
+
+ /*
+ if (panel->use_alt_session_defaults)
+ {
+ panel->session_cur_gravity = PAPP_GRAVITY_END;
+ panel->session_run_first_time = True;
+ }
+ */
+
+ if (getenv("HOME") == NULL)
+ {
+ fprintf(stderr, "mbdock: unable to get home directory, is HOME set?\n");
+ panel->session_preexisting_lock = False;
+ return;
+ }
+
+ snprintf(sessionfile, 512, "%s/.matchbox", getenv("HOME"));
+
+ /* Check if ~/.matchbox exists and create if not */
+ if (stat(sessionfile, &st) != 0 /* || !S_ISDIR(st.st_mode) */
+ || !panel->use_session)
+ {
+ if (panel->use_session)
+ {
+ fprintf(stderr, "mbdock: creating %s directory for session files\n",
+ sessionfile);
+ mkdir(sessionfile, 0755);
+ }
+ panel->session_cur_gravity = PAPP_GRAVITY_END;
+ panel->session_run_first_time = True;
+ if (!panel->use_alt_session_defaults)
+ panel->session_defaults_cur_pos = strdup(DEFAULT_SESSIONS);
+ }
+ else
+ {
+ /* We have a ~/.matchbox , see if we have a session file
+ and set defualts if not.
+ */
+ if (panel->system_tray_id)
+ snprintf(sessionfile, 512, "%s/.matchbox/%s.%i", getenv("HOME"),
+ PANELFILE, panel->system_tray_id );
+ else
+ snprintf(sessionfile, 512, "%s/.matchbox/%s",
+ getenv("HOME"), PANELFILE );
+
+ if ((panel->session_fp = fopen(sessionfile, "r")) == NULL)
+ {
+ fprintf(stderr,
+ "mbpanel: Session file does not exist ( tryed %s )\n",
+ sessionfile);
+ if (!panel->use_alt_session_defaults)
+ {
+ panel->session_defaults_cur_pos = strdup(DEFAULT_SESSIONS);
+ }
+ panel->session_cur_gravity = PAPP_GRAVITY_START;
+ panel->session_run_first_time = True;
+ }
+ else
+ {
+ DBG("%s() opened %s\n", __func__, sessionfile);
+ }
+ }
+
+ panel->session_preexisting_lock = True; /* we are loading session data */
+ panel->session_entry_cur[0] = 0;
+
+ session_preexisting_start_next(panel);
+
+}
+
+void session_save(MBPanel *panel)
+{
+ char *sessionfile = alloca(sizeof(char)*255);
+
+ int i = 0;
+ MBPanelApp *papp = NULL;
+ MBPanelApp *papp_heads[] = { panel->apps_start_head,
+ panel->apps_end_head };
+
+ DBG("%s() called\n", __func__);
+
+ if (!panel->use_session
+ || session_preexisting_restarting(panel))
+ return;
+
+ if (getenv("HOME") == NULL)
+ {
+ fprintf(stderr, "mbdock: unable to get home directory, is HOME set?\n");
+ return;
+ }
+
+ if (panel->system_tray_id)
+ snprintf(sessionfile, 255, "%s/.matchbox/%s.%i", getenv("HOME"),
+ PANELFILE, panel->system_tray_id );
+ else
+ snprintf(sessionfile, 255, "%s/.matchbox/%s",
+ getenv("HOME"), PANELFILE );
+
+ if ((panel->session_fp = fopen(sessionfile, "w")) == NULL)
+ {
+ fprintf(stderr,"mbdock: Unable to create Session file ( %s )\n",
+ sessionfile);
+ return;
+ }
+
+ DBG("%s() still called\n", __func__);
+
+ while (i < 2)
+ {
+ papp = papp_heads[i];
+ while( papp != NULL )
+ {
+ DBG("%s() writing %s\n", __func__, papp->cmd_str);
+ if (papp->cmd_str)
+ {
+ DBG("%s() writing %s\n", __func__, papp->cmd_str);
+ fprintf(panel->session_fp, "%s\n", papp->cmd_str);
+ }
+ papp = papp->next;
+ }
+ fprintf(panel->session_fp, "\t\n" );
+ i++;
+ }
+
+ fclose(panel->session_fp);
+}
+
+Bool
+session_preexisting_restarting(MBPanel *panel)
+{
+ return panel->session_preexisting_lock;
+}
+
+Bool
+session_preexisting_start_next(MBPanel *panel)
+{
+ if (!session_preexisting_restarting(panel)) return False;
+
+ if (panel->session_entry_cur[0] == '\0'
+ && session_preexisting_get_next(panel))
+ {
+ DBG("%s() starting %s\n", __func__, panel->session_entry_cur);
+ panel->session_needed_pid = util_fork_exec(panel->session_entry_cur);
+ return True;
+ }
+ return False;
+}
+
+Bool
+session_preexisting_win_matches_wanted(MBPanel *panel, Window win,
+ char *win_cmd)
+{
+ pid_t win_pid = 0;
+ if (!session_preexisting_restarting(panel)) return False;
+
+ DBG("%s() called\n", __func__);
+
+ if (panel->session_entry_cur) /* what were waiting on */
+ {
+ /* Check if its got the pid we expect */
+ win_pid = util_get_window_pid_from_prop(panel, win);
+
+ DBG("%s() win pid is %i\n", __func__, win_pid);
+
+ if (win_pid && win_pid == panel->session_needed_pid)
+ return True;
+
+ DBG("%s() pid failed, comparing '%s' vs '%s'\n", __func__,
+ win_cmd, panel->session_entry_cur );
+
+ /* check cmd str */
+ if (win_cmd && !strncmp(win_cmd, panel->session_entry_cur,
+ strlen(win_cmd)))
+ return True;
+ }
+
+ return False;
+}
+
+void
+session_preexisting_clear_current(MBPanel *panel)
+{
+ panel->session_entry_cur[0] = '\0';
+}
+
+Bool
+session_preexisting_handle_timeouts(MBPanel *panel)
+{
+ if (!session_preexisting_restarting(panel)) return False;
+
+ DBG("%s() called\n", __func__);
+
+ /* catch session timeouts */
+ if (panel->session_entry_cur[0] != '\0')
+ {
+ if ( (time(NULL)-panel->session_start_time) > SESSION_TIMEOUT)
+ {
+ fprintf(stderr, "Session timeout on %s\n", panel->session_entry_cur);
+ session_preexisting_clear_current(panel);
+ session_preexisting_start_next(panel);
+ }
+ }
+ return True;
+}
+
+Bool
+session_preexisting_get_next(MBPanel *panel) /* session_restarting_get_next */
+{
+ char *tmp;
+
+ if (!session_preexisting_restarting(panel)) return False;
+
+ panel->session_init_offset = 10;
+
+ if (panel->session_run_first_time)
+ {
+ if (*panel->session_defaults_cur_pos != '\0')
+ {
+ char *prev_pos = panel->session_defaults_cur_pos;
+ while ( *panel->session_defaults_cur_pos != '\0')
+ {
+ if ( *panel->session_defaults_cur_pos == ',')
+ {
+ *panel->session_defaults_cur_pos = '\0';
+ panel->session_defaults_cur_pos++;
+ break;
+ }
+ panel->session_defaults_cur_pos++;
+ }
+
+ strncpy(panel->session_entry_cur, prev_pos, 512);
+ }
+ else
+ {
+ panel->session_run_first_time = False;
+ panel->session_preexisting_lock = False;
+ session_save(panel);
+ return False;
+ }
+ }
+ else
+ {
+
+ if (fgets(panel->session_entry_cur, 512, panel->session_fp) == NULL)
+ {
+ fclose(panel->session_fp); /* All sessions done */
+ panel->session_preexisting_lock = False;
+ session_save(panel);
+ return False;
+ }
+
+ /* tab + newline -> change the session gravity */
+ if (!strcmp(panel->session_entry_cur, "\t\n"))
+ {
+ panel->session_cur_gravity = PAPP_GRAVITY_END;
+ return session_preexisting_get_next(panel);
+ }
+
+ if ( panel->session_entry_cur[strlen(panel->session_entry_cur)-1] == '\n')
+ panel->session_entry_cur[strlen(panel->session_entry_cur)-1] = '\0';
+
+ if ( (tmp = strstr(panel->session_entry_cur, "\t\t")) != NULL )
+ {
+ panel->session_init_offset = atoi(tmp);
+ *tmp = '\0';
+ }
+ }
+
+ panel->session_start_time = time(NULL);
+ return True;
+}
diff --git a/src/session.h b/src/session.h
new file mode 100644
index 0000000..05b527b
--- /dev/null
+++ b/src/session.h
@@ -0,0 +1,37 @@
+#ifndef _HAVE_PANEL_SESSION_H
+#define _HAVE_PANEL_SESSION_H
+
+#include "panel.h"
+
+#ifdef DEBUG
+#define PANELFILE "mbdock.session.debug"
+#else
+#define PANELFILE "mbdock.session"
+#endif
+
+void
+session_destroy(MBPanel *panel);
+
+void
+session_set_defaults(MBPanel *panel, char *defaults);
+
+void session_init(MBPanel *panel);
+
+void session_save(MBPanel *panel);
+
+Bool session_preexisting_restarting(MBPanel *panel);
+
+Bool session_preexisting_start_next(MBPanel *panel);;
+
+Bool session_preexisting_win_matches_wanted(MBPanel *panel, Window win,
+ char *win_cmd);
+
+void session_preexisting_clear_current(MBPanel *panel);
+
+Bool session_preexisting_handle_timeouts(MBPanel *panel);
+
+Bool session_preexisting_get_next(MBPanel *panel);
+
+
+
+#endif