diff options
Diffstat (limited to 'src/msg.c')
-rw-r--r-- | src/msg.c | 670 |
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; +} + + |