/* -*-c-*- */ /* 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 Place, Suite 330, Boston, MA 02111-1307 USA */ /* ---------------------------- included header files ---------------------- */ #include "config.h" #include #include "libs/fvwmlib.h" #include "libs/Picture.h" #include "libs/Graphics.h" #include "libs/PictureGraphics.h" #include "libs/Rectangles.h" #include "fvwm.h" #include "externs.h" #include "execcontext.h" #include "misc.h" #include "screen.h" #include "menudim.h" #include "menustyle.h" #include "menuitem.h" #include "decorations.h" /* ---------------------------- local definitions -------------------------- */ /* ---------------------------- local macros ------------------------------- */ /* ---------------------------- imports ------------------------------------ */ /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ /* ---------------------------- forward declarations ----------------------- */ /* ---------------------------- local variables ---------------------------- */ /* ---------------------------- exported variables (globals) --------------- */ /* ---------------------------- local functions ---------------------------- */ static void clear_menu_item_background( MenuPaintItemParameters *mpip, int x, int y, int w, int h) { MenuStyle *ms = mpip->ms; if (!ST_HAS_MENU_CSET(ms) && ST_FACE(ms).type == GradientMenu && (ST_FACE(ms).gradient_type == D_GRADIENT || ST_FACE(ms).gradient_type == B_GRADIENT)) { XEvent e; e.xexpose.x = x; e.xexpose.y = y; e.xexpose.width = w; e.xexpose.height = h; mpip->cb_reset_bg(mpip->cb_mr, &e); } else { XClearArea(dpy, mpip->w, x, y, w, h, False); } } /* * * Draws two horizontal lines to form a separator * */ static void draw_separator( Window w, GC TopGC, GC BottomGC, int x1, int y, int x2) { XDrawLine(dpy, w, TopGC , x1, y, x2, y); XDrawLine(dpy, w, BottomGC, x1-1, y+1, x2+1, y+1); return; } /* * * Draws a tear off bar. Similar to a separator, but with a dashed line. * */ static void draw_tear_off_bar( Window w, GC TopGC, GC BottomGC, int x1, int y, int x2) { XGCValues xgcv; int width; int offset; xgcv.line_style = LineOnOffDash; xgcv.dashes = MENU_TEAR_OFF_BAR_DASH_WIDTH; XChangeGC(dpy, TopGC, GCLineStyle | GCDashList, &xgcv); XChangeGC(dpy, BottomGC, GCLineStyle | GCDashList, &xgcv); width = (x2 - x1 + 1); offset = (width / MENU_TEAR_OFF_BAR_DASH_WIDTH) * MENU_TEAR_OFF_BAR_DASH_WIDTH; offset = (width - offset) / 2; x1 += offset; x2 += offset; XDrawLine(dpy, w, TopGC, x1, y, x2, y); XDrawLine(dpy, w, BottomGC, x1, y + 1, x2, y + 1); xgcv.line_style = LineSolid; XChangeGC(dpy, TopGC, GCLineStyle, &xgcv); XChangeGC(dpy, BottomGC, GCLineStyle, &xgcv); return; } static void draw_highlight_background( struct MenuPaintItemParameters *mpip, int x, int y, int width, int height, colorset_t *cs, GC gc) { if (cs != NULL && cs->pixmap && cs->pixmap_type != PIXMAP_TILED) { Pixmap p; p = CreateOffsetBackgroundPixmap( dpy, mpip->w, 0, 0, width, height, cs, Pdepth, gc, False); switch (cs->pixmap_type) { case PIXMAP_STRETCH_X: /* todo: optimize to only create one pixmap and gc per * mr. */ case PIXMAP_STRETCH_Y: { XGCValues gcv; int gcm; GC bgc; gcv.tile = p; gcv.fill_style = FillTiled; gcm = GCFillStyle | GCTile; /* vertcal gradients has to be aligned properly */ if (cs->pixmap_type == PIXMAP_STRETCH_Y) { gcv.ts_y_origin = y; gcm|=GCTileStipYOrigin; } else if (cs->pixmap_type == PIXMAP_STRETCH_X) { gcv.ts_x_origin = x; gcm|=GCTileStipXOrigin; } bgc = fvwmlib_XCreateGC(dpy, mpip->w, gcm, &gcv); XFillRectangle(dpy, mpip->w, bgc, x, y, width, height); XFreeGC(dpy, bgc); break; } default: XCopyArea(dpy, p, mpip->w, gc, 0, 0, width, height, x, y); break; } XFreePixmap(dpy, p); } else { XFillRectangle(dpy, mpip->w, gc, x, y, width, height); } } /* ---------------------------- interface functions ------------------------ */ /* Allocates a new, empty menu item */ struct MenuItem *menuitem_create(void) { MenuItem *mi; mi = (MenuItem *)safemalloc(sizeof(MenuItem)); memset(mi, 0, sizeof(MenuItem)); return mi; } /* Frees a menu item and all of its allocated resources. */ void menuitem_free(struct MenuItem *mi) { int i; if (!mi) { return; } for (i = 0; i < MAX_MENU_ITEM_LABELS; i++) { if (MI_LABEL(mi)[i] != NULL) { free(MI_LABEL(mi)[i]); } } if (MI_ACTION(mi) != NULL) { free(MI_ACTION(mi)); } if (MI_PICTURE(mi)) { PDestroyFvwmPicture(dpy, MI_PICTURE(mi)); } for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++) { if (MI_MINI_ICON(mi)[i]) { PDestroyFvwmPicture(dpy, MI_MINI_ICON(mi)[i]); } } free(mi); return; } /* Duplicate a menu item into newly allocated memory. The new item is * completely independent of the old one. */ struct MenuItem *menuitem_clone(struct MenuItem *mi) { MenuItem *new_mi; int i; /* copy everything */ new_mi = (MenuItem *)safemalloc(sizeof(MenuItem)); memcpy(new_mi, mi, sizeof(MenuItem)); /* special treatment for a few parts */ MI_NEXT_ITEM(new_mi) = NULL; MI_PREV_ITEM(new_mi) = NULL; MI_WAS_DESELECTED(new_mi) = 0; if (MI_ACTION(mi) != NULL) { MI_ACTION(new_mi) = safestrdup(MI_ACTION(mi)); } for (i = 0; i < MAX_MENU_ITEM_LABELS; i++) { if (MI_LABEL(mi)[i] != NULL) { MI_LABEL(new_mi)[i] = strdup(MI_LABEL(mi)[i]); } } if (MI_PICTURE(mi) != NULL) { MI_PICTURE(new_mi) = PCloneFvwmPicture(MI_PICTURE(mi)); } for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++) { if (MI_MINI_ICON(mi)[i] != NULL) { MI_MINI_ICON(new_mi)[i] = PCloneFvwmPicture(MI_MINI_ICON(mi)[i]); } } return new_mi; } /* Calculate the size of the various parts of the item. The sizes are returned * through mipst. */ void menuitem_get_size( struct MenuItem *mi, struct MenuItemPartSizesT *mipst, FlocaleFont *font, Bool do_reverse_icon_order) { int i; int j; int w; memset(mipst, 0, sizeof(MenuItemPartSizesT)); if (MI_IS_POPUP(mi)) { mipst->triangle_width = MENU_TRIANGLE_WIDTH; } else if (MI_IS_TITLE(mi) && !MI_HAS_PICTURE(mi)) { Bool is_formatted = False; /* titles stretch over the whole menu width, so count the * maximum separately if the title is unformatted. */ for (j = 1; j < MAX_MENU_ITEM_LABELS; j++) { if (MI_LABEL(mi)[j] != NULL) { is_formatted = True; break; } else { MI_LABEL_OFFSET(mi)[j] = 0; } } if (!is_formatted && MI_LABEL(mi)[0] != NULL) { MI_LABEL_STRLEN(mi)[0] = strlen(MI_LABEL(mi)[0]); w = FlocaleTextWidth( font, MI_LABEL(mi)[0], MI_LABEL_STRLEN(mi)[0]); MI_LABEL_OFFSET(mi)[0] = w; MI_IS_TITLE_CENTERED(mi) = True; if (mipst->title_width < w) { mipst->title_width = w; } return; } } /* regular item or formatted title */ for (i = 0; i < MAX_MENU_ITEM_LABELS; i++) { if (MI_LABEL(mi)[i]) { MI_LABEL_STRLEN(mi)[i] = strlen(MI_LABEL(mi)[i]); w = FlocaleTextWidth( font, MI_LABEL(mi)[i], MI_LABEL_STRLEN(mi)[i]); MI_LABEL_OFFSET(mi)[i] = w; if (mipst->label_width[i] < w) { mipst->label_width[i] = w; } } } if (MI_PICTURE(mi) && mipst->picture_width < MI_PICTURE(mi)->width) { mipst->picture_width = MI_PICTURE(mi)->width; } for (i = 0; i < MAX_MENU_ITEM_MINI_ICONS; i++) { if (MI_MINI_ICON(mi)[i]) { int k; /* Reverse mini icon order for left submenu style. */ k = (do_reverse_icon_order == True) ? MAX_MENU_ITEM_MINI_ICONS - 1 - i : i; mipst->icon_width[k] = MI_MINI_ICON(mi)[i]->width; } } return; } /* * * Procedure: * menuitem_paint - draws a single entry in a popped up menu * * mr - the menu instance that holds the menu item * mi - the menu item to redraw * fw - the FvwmWindow structure to check against allowed functions * */ void menuitem_paint( struct MenuItem *mi, struct MenuPaintItemParameters *mpip) { struct MenuStyle *ms = mpip->ms; struct MenuDimensions *dim = mpip->dim; static FlocaleWinString *fws = NULL; int y_offset; int text_y; int y_height; int x; int y; int lit_x_start; int lit_x_end; gc_quad_t gcs; gc_quad_t off_gcs; int cs = -1; int off_cs; FvwmRenderAttributes fra; /*Pixel fg, fgsh;*/ int relief_thickness = ST_RELIEF_THICKNESS(ms); Bool is_item_selected; Bool item_cleared = False; Bool xft_clear = False; Bool empty_inter = False; XRectangle b; Region region = None; int i; int sx1; int sx2; FlocaleFont* font; if (!mi) { return; } is_item_selected = (mi == mpip->selected_item); if (MI_IS_TITLE(mi)) { font = ST_PTITLEFONT(ms); } else { font = ST_PSTDFONT(ms); } y_offset = MI_Y_OFFSET(mi); y_height = MI_HEIGHT(mi); if (MI_IS_SELECTABLE(mi)) { text_y = y_offset + MDIM_ITEM_TEXT_Y_OFFSET(*dim); } else { text_y = y_offset + font->ascent + ST_TITLE_GAP_ABOVE(ms); } /* center text vertically if the pixmap is taller */ if (MI_PICTURE(mi)) { text_y += MI_PICTURE(mi)->height; } for (i = 0; i < mpip->used_mini_icons; i++) { y = 0; if (MI_MINI_ICON(mi)[i]) { if (MI_MINI_ICON(mi)[i]->height > y) { y = MI_MINI_ICON(mi)[i]->height; } } y -= font->height; if (y > 1) { text_y += y / 2; } } off_cs = ST_HAS_MENU_CSET(ms) ? ST_CSET_MENU(ms) : -1; /* Note: it's ok to pass a NULL label to is_function_allowed. */ if ( !IS_EWMH_DESKTOP_FW(mpip->fw) && !is_function_allowed( MI_FUNC_TYPE(mi), MI_LABEL(mi)[0], mpip->fw, RQORIG_PROGRAM_US, False)) { gcs = ST_MENU_STIPPLE_GCS(ms); off_gcs = gcs; off_cs = ST_HAS_GREYED_CSET(ms) ? ST_CSET_GREYED(ms) : -1; } else if (is_item_selected) { gcs = ST_MENU_ACTIVE_GCS(ms); off_gcs = ST_MENU_INACTIVE_GCS(ms); } else if (MI_IS_TITLE(mi)) { gcs = ST_MENU_TITLE_GCS(ms); off_gcs = ST_MENU_INACTIVE_GCS(ms); } else { gcs = ST_MENU_INACTIVE_GCS(ms); off_gcs = ST_MENU_INACTIVE_GCS(ms); } if (is_item_selected) { cs = (ST_HAS_ACTIVE_CSET(ms)) ? ST_CSET_ACTIVE(ms) : -1; } else if (MI_IS_TITLE(mi)) { cs = (ST_HAS_TITLE_CSET(ms)) ? ST_CSET_TITLE(ms) : off_cs; } else { cs = off_cs; } /* * Hilight the item. */ if (FftSupport && ST_PSTDFONT(ms)->fftf.fftfont != NULL) { xft_clear = True; } /* Hilight or clear the background. */ lit_x_start = -1; lit_x_end = -1; if (is_item_selected && (ST_DO_HILIGHT_BACK(ms) || ST_DO_HILIGHT_FORE(ms))) { /* Hilight the background. */ if (MDIM_HILIGHT_WIDTH(*dim) - 2 * relief_thickness > 0) { lit_x_start = MDIM_HILIGHT_X_OFFSET(*dim) + relief_thickness; lit_x_end = lit_x_start + MDIM_HILIGHT_WIDTH(*dim) - 2 * relief_thickness; if (ST_DO_HILIGHT_BACK(ms)) { draw_highlight_background( mpip, lit_x_start, y_offset + relief_thickness, lit_x_end - lit_x_start, y_height - relief_thickness, (cs >= 0 ? &Colorset[cs] : NULL), gcs.back_gc); item_cleared = True; } } } else if ((MI_WAS_DESELECTED(mi) && (relief_thickness > 0 || ST_DO_HILIGHT_BACK(ms) || ST_DO_HILIGHT_FORE(ms)) && (ST_FACE(ms).type != GradientMenu || ST_HAS_MENU_CSET(ms)))) { int x1; int x2; /* we clear if xft_clear and !ST_HAS_MENU_CSET(ms) as the * non colorset code is too complicate ... olicha */ int d = 0; if (MI_PREV_ITEM(mi) && mpip->selected_item == MI_PREV_ITEM(mi)) { /* Don't paint over the hilight relief. */ d = relief_thickness; } /* Undo the hilighting. */ x1 = min( MDIM_HILIGHT_X_OFFSET(*dim), MDIM_ITEM_X_OFFSET(*dim)); x2 = max( MDIM_HILIGHT_X_OFFSET(*dim) + MDIM_HILIGHT_WIDTH(*dim), MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim)); clear_menu_item_background( mpip, x1, y_offset + d, x2 - x1, y_height + relief_thickness - d); item_cleared = True; } else if (MI_IS_TITLE(mi)) { lit_x_start = MDIM_ITEM_X_OFFSET(*dim); lit_x_end = lit_x_start + MDIM_ITEM_WIDTH(*dim); /* Hilight the background. */ if ( MDIM_HILIGHT_WIDTH(*dim) > 0 && ST_DO_HILIGHT_TITLE_BACK(ms)) { draw_highlight_background( mpip, lit_x_start, y_offset + relief_thickness, lit_x_end - lit_x_start, y_height - relief_thickness, (cs >= 0 ? &Colorset[cs] : NULL), gcs.back_gc); item_cleared = True; } } MI_WAS_DESELECTED(mi) = False; memset(&fra, 0, sizeof(fra)); fra.mask = 0; /* Hilight 3D */ if (is_item_selected && relief_thickness > 0) { GC rgc; GC sgc; rgc = gcs.hilight_gc; sgc = gcs.shadow_gc; if (ST_IS_ITEM_RELIEF_REVERSED(ms)) { GC tgc = rgc; /* swap gcs for reversed relief */ rgc = sgc; sgc = tgc; } if (MDIM_HILIGHT_WIDTH(*dim) - 2 * relief_thickness > 0) { /* The relief reaches down into the next item, hence * the value for the second y coordinate: * MI_HEIGHT(mi) + 1 */ RelieveRectangle( dpy, mpip->w, MDIM_HILIGHT_X_OFFSET(*dim), y_offset, MDIM_HILIGHT_WIDTH(*dim) - 1, MI_HEIGHT(mi) - 1 + relief_thickness, rgc, sgc, relief_thickness); } } /* * Draw the item itself. */ /* Calculate the separator offsets. */ if (ST_HAS_LONG_SEPARATORS(ms)) { sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness; sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 - relief_thickness; } else { sx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness + MENU_SEPARATOR_SHORT_X_OFFSET; sx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 - relief_thickness - MENU_SEPARATOR_SHORT_X_OFFSET; } if (MI_IS_SEPARATOR(mi)) { if (sx1 < sx2) { /* It's a separator. */ draw_separator( mpip->w, gcs.shadow_gc, gcs.hilight_gc, sx1, y_offset + y_height - MENU_SEPARATOR_HEIGHT, sx2); /* Nothing else to do. */ } return; } else if (MI_IS_TEAR_OFF_BAR(mi)) { int tx1; int tx2; tx1 = MDIM_ITEM_X_OFFSET(*dim) + relief_thickness + MENU_TEAR_OFF_BAR_X_OFFSET; tx2 = MDIM_ITEM_X_OFFSET(*dim) + MDIM_ITEM_WIDTH(*dim) - 1 - relief_thickness - MENU_TEAR_OFF_BAR_X_OFFSET; if (tx1 < tx2) { /* It's a tear off bar. */ draw_tear_off_bar( mpip->w, gcs.shadow_gc, gcs.hilight_gc, tx1, y_offset + relief_thickness + MENU_TEAR_OFF_BAR_Y_OFFSET, tx2); } /* Nothing else to do. */ return; } else if (MI_IS_TITLE(mi)) { /* Separate the title. */ if (ST_TITLE_UNDERLINES(ms) > 0 && !mpip->flags.is_first_item) { int add = (MI_IS_SELECTABLE(MI_PREV_ITEM(mi))) ? relief_thickness : 0; text_y += MENU_SEPARATOR_HEIGHT + add; y = y_offset + add; if (sx1 < sx2) { draw_separator( mpip->w, gcs.shadow_gc, gcs.hilight_gc, sx1, y, sx2); } } /* Underline the title. */ switch (ST_TITLE_UNDERLINES(ms)) { case 0: break; case 1: if (MI_NEXT_ITEM(mi) != NULL) { y = y_offset + y_height - MENU_SEPARATOR_HEIGHT; draw_separator( mpip->w, gcs.shadow_gc, gcs.hilight_gc, sx1, y, sx2); } break; default: for (i = ST_TITLE_UNDERLINES(ms); i-- > 0; ) { y = y_offset + y_height - 1 - i * MENU_UNDERLINE_HEIGHT; XDrawLine( dpy, mpip->w, gcs.shadow_gc, sx1, y, sx2, y); } break; } } /* * Draw the labels. */ if (fws == NULL) { FlocaleAllocateWinString(&fws); } fws->win = mpip->w; fws->y = text_y; fws->flags.has_colorset = 0; b.y = text_y - font->ascent; b.height = font->height + 1; /* ? */ if (!item_cleared && mpip->ev) { int u,v; if (!frect_get_seg_intersection( mpip->ev->xexpose.y, mpip->ev->xexpose.height, b.y, b.height, &u, &v)) { /* empty intersection */ empty_inter = True; } b.y = u; b.height = v; } for (i = MAX_MENU_ITEM_LABELS; i-- > 0; ) { if (!empty_inter && MI_LABEL(mi)[i] && *(MI_LABEL(mi)[i])) { Bool draw_string = True; int text_width; int tmp_cs; if (MI_LABEL_OFFSET(mi)[i] >= lit_x_start && MI_LABEL_OFFSET(mi)[i] < lit_x_end) { /* label is in hilighted area */ fws->gc = gcs.fore_gc; tmp_cs = cs; } else { /* label is in unhilighted area */ fws->gc = off_gcs.fore_gc; tmp_cs = off_cs; } if (tmp_cs >= 0) { fws->colorset = &Colorset[tmp_cs]; fws->flags.has_colorset = 1; } fws->str = MI_LABEL(mi)[i]; b.x = fws->x = MI_LABEL_OFFSET(mi)[i]; b.width = text_width = FlocaleTextWidth( font, fws->str, strlen(fws->str)); if (!item_cleared && mpip->ev) { int s_x,s_w; if (frect_get_seg_intersection( mpip->ev->xexpose.x, mpip->ev->xexpose.width, fws->x, text_width, &s_x, &s_w)) { b.x = s_x; b.width = s_w; region = XCreateRegion(); XUnionRectWithRegion( &b, region, region); fws->flags.has_clip_region = True; fws->clip_region = region; draw_string = True; XSetRegion(dpy, fws->gc, region); } else { /* empty intersection */ draw_string = False; } } if (draw_string) { if (!item_cleared && xft_clear) { clear_menu_item_background( mpip, b.x, b.y, b.width, b.height); } FlocaleDrawString(dpy, font, fws, 0); /* hot key */ if (MI_HAS_HOTKEY(mi) && !MI_IS_TITLE(mi) && (!MI_IS_HOTKEY_AUTOMATIC(mi) || ST_USE_AUTOMATIC_HOTKEYS(ms)) && MI_HOTKEY_COLUMN(mi) == i) { FlocaleDrawUnderline( dpy, ST_PSTDFONT(ms), fws, MI_HOTKEY_COFFSET(mi)); } } } if (region) { XDestroyRegion(region); region = None; fws->flags.has_clip_region = False; fws->clip_region = None; XSetClipMask(dpy, fws->gc, None); } } /* * Draw the submenu triangle. */ if (MI_IS_POPUP(mi)) { GC tmp_gc; if (MDIM_TRIANGLE_X_OFFSET(*dim) >= lit_x_start && MDIM_TRIANGLE_X_OFFSET(*dim) < lit_x_end && is_item_selected) { /* triangle is in hilighted area */ if (ST_TRIANGLES_USE_FORE(ms)) { tmp_gc = gcs.fore_gc; } else { tmp_gc = gcs.hilight_gc; } } else { /* triangle is in unhilighted area */ if (ST_TRIANGLES_USE_FORE(ms)) { tmp_gc = off_gcs.fore_gc; } else { tmp_gc = off_gcs.hilight_gc; } } y = y_offset + (y_height - MENU_TRIANGLE_HEIGHT + relief_thickness) / 2; if (ST_TRIANGLES_USE_FORE(ms)) { DrawTrianglePattern( dpy, mpip->w, tmp_gc, tmp_gc, tmp_gc, MDIM_TRIANGLE_X_OFFSET(*dim), y, MENU_TRIANGLE_WIDTH, MENU_TRIANGLE_HEIGHT, 0, (mpip->flags.is_left_triangle) ? 'l' : 'r', ST_HAS_TRIANGLE_RELIEF(ms), !ST_HAS_TRIANGLE_RELIEF(ms), is_item_selected); } else { DrawTrianglePattern( dpy, mpip->w, gcs.hilight_gc, gcs.shadow_gc, tmp_gc, MDIM_TRIANGLE_X_OFFSET(*dim), y, MENU_TRIANGLE_WIDTH, MENU_TRIANGLE_HEIGHT, 0, (mpip->flags.is_left_triangle) ? 'l' : 'r', ST_HAS_TRIANGLE_RELIEF(ms), !ST_HAS_TRIANGLE_RELIEF(ms), is_item_selected); } } /* * Draw the item picture. */ if (MI_PICTURE(mi)) { GC tmp_gc; int tmp_cs; Bool draw_picture = True; x = menudim_middle_x_offset(mpip->dim) - MI_PICTURE(mi)->width / 2; y = y_offset + ((MI_IS_SELECTABLE(mi)) ? relief_thickness : 0); if (x >= lit_x_start && x < lit_x_end) { tmp_gc = gcs.fore_gc; tmp_cs = cs; } else { tmp_gc = off_gcs.fore_gc; tmp_cs = off_cs; } fra.mask = FRAM_DEST_IS_A_WINDOW; if (tmp_cs >= 0) { fra.mask |= FRAM_HAVE_ICON_CSET; fra.colorset = &Colorset[tmp_cs]; } b.x = x; b.y = y; b.width = MI_PICTURE(mi)->width; b.height = MI_PICTURE(mi)->height; if (!item_cleared && mpip->ev) { if (!frect_get_intersection( mpip->ev->xexpose.x, mpip->ev->xexpose.y, mpip->ev->xexpose.width, mpip->ev->xexpose.height, b.x, b.y, b.width, b.height, &b)) { draw_picture = False; } } if (draw_picture) { if ( !item_cleared && (MI_PICTURE(mi)->alpha != None || (tmp_cs >=0 && Colorset[tmp_cs].icon_alpha_percent < 100))) { clear_menu_item_background( mpip, b.x, b.y, b.width, b.height); } PGraphicsRenderPicture( dpy, mpip->w, MI_PICTURE(mi), &fra, mpip->w, tmp_gc, Scr.MonoGC, Scr.AlphaGC, b.x - x, b.y - y, b.width, b.height, b.x, b.y, b.width, b.height, False); } } /* * Draw the mini icons. */ for (i = 0; i < mpip->used_mini_icons; i++) { int k; Bool draw_picture = True; /* We need to reverse the mini icon order for left submenu * style. */ k = (ST_USE_LEFT_SUBMENUS(ms)) ? mpip->used_mini_icons - 1 - i : i; if (MI_MINI_ICON(mi)[i]) { GC tmp_gc; int tmp_cs; if (MI_PICTURE(mi)) { y = y_offset + MI_HEIGHT(mi) - MI_MINI_ICON(mi)[i]->height; } else { y = y_offset + (MI_HEIGHT(mi) + ((MI_IS_SELECTABLE(mi)) ? relief_thickness : 0) - MI_MINI_ICON(mi)[i]->height) / 2; } if (MDIM_ICON_X_OFFSET(*dim)[k] >= lit_x_start && MDIM_ICON_X_OFFSET(*dim)[k] < lit_x_end) { /* icon is in hilighted area */ tmp_gc = gcs.fore_gc; tmp_cs = cs; } else { /* icon is in unhilighted area */ tmp_gc = off_gcs.fore_gc; tmp_cs = off_cs; } fra.mask = FRAM_DEST_IS_A_WINDOW; if (tmp_cs >= 0) { fra.mask |= FRAM_HAVE_ICON_CSET; fra.colorset = &Colorset[tmp_cs]; } b.x = MDIM_ICON_X_OFFSET(*dim)[k]; b.y = y; b.width = MI_MINI_ICON(mi)[i]->width; b.height = MI_MINI_ICON(mi)[i]->height; if (!item_cleared && mpip->ev) { if (!frect_get_intersection( mpip->ev->xexpose.x, mpip->ev->xexpose.y, mpip->ev->xexpose.width, mpip->ev->xexpose.height, b.x, b.y, b.width, b.height, &b)) { draw_picture = False; } } if (draw_picture) { if (!item_cleared && (MI_MINI_ICON(mi)[i]->alpha != None || (tmp_cs >=0 && Colorset[tmp_cs].icon_alpha_percent < 100))) { clear_menu_item_background( mpip, b.x, b.y, b.width, b.height); } PGraphicsRenderPicture( dpy, mpip->w, MI_MINI_ICON(mi)[i], &fra, mpip->w, tmp_gc, Scr.MonoGC, Scr.AlphaGC, b.x - MDIM_ICON_X_OFFSET(*dim)[k], b.y - y, b.width, b.height, b.x, b.y, b.width, b.height, False); } } } return; } /* returns the center y coordinate of the menu item */ int menuitem_middle_y_offset(struct MenuItem *mi, struct MenuStyle *ms) { int r; if (!mi) { return ST_BORDER_WIDTH(ms); } r = (MI_IS_SELECTABLE(mi)) ? ST_RELIEF_THICKNESS(ms) : 0; return MI_Y_OFFSET(mi) + (MI_HEIGHT(mi) + r) / 2; }