aboutsummaryrefslogtreecommitdiffstats
path: root/src/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/msg.c')
-rw-r--r--src/msg.c670
1 files changed, 670 insertions, 0 deletions
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;
+}
+
+