# HG changeset patch # User Jan D # Date 1271526183 -7200 # Node ID 9a798edc503b66fad31abe38f0f477c27d60733e # Parent 1da056389889b7ecc198797cca11000a61d04d56 Don't redraw lucid menus more than needed. Use double buffer to reduce flicker. * xlwmenu.c: Include Shell.h, remove duplicate declaration of XlwMenuRedisplay. (display_menu_item): Replace ws->window with ws->pixmap, remove call to XftDrawRect. (display_menu): Remove this and that argument. Remove just_compute_this_one_p. Fill pixmap at start and copy it to window at end. (expose_cb): New function. (make_windows_if_needed): Replace XCreateWindow with XtCreatePopup. Add eventhandler for expose to expose_cb. Remove creation of xft_draw. (create_pixmap_for_menu): New function. (remap_menubar): Pop down menus that aren't the same as in old_stack. Set width, heigh, x, y on widget with XtVaSetValues. Call create_pixmap_for_menu. Replace XUnmapWindow with XtPopdown. Remowe two last parameters to display_menu. (map_event_to_widget_value, XlwMenuRedisplay, Key, Select) (pop_up_menu): Remowe two last parameters to display_menu. (XlwMenuRealize): Call create_pixmap_for_menu, set w and pixmap. Remove call to XftDrawCreate. (XlwMenuDestroy): Free pixmap. Call XtDestroyWidget instead of XDestroyWindow. (handle_motion_event): Only call handle_single_motion_event once. * xlwmenuP.h (window_state): Add pixmap and w. diff -r 1da056389889 -r 9a798edc503b lwlib/ChangeLog --- a/lwlib/ChangeLog Sat Apr 17 11:53:55 2010 -0400 +++ b/lwlib/ChangeLog Sat Apr 17 19:43:03 2010 +0200 @@ -1,3 +1,32 @@ +2010-04-17 Jan Djärv + + * xlwmenu.c: Include Shell.h, remove duplicate declaration of + XlwMenuRedisplay. + (display_menu_item): Replace ws->window with ws->pixmap, remove + call to XftDrawRect. + (display_menu): Remove this and that argument. Remove + just_compute_this_one_p. Fill pixmap at start and copy it to window + at end. + (expose_cb): New function. + (make_windows_if_needed): Replace XCreateWindow with XtCreatePopup. + Add eventhandler for expose to expose_cb. Remove creation of + xft_draw. + (create_pixmap_for_menu): New function. + (remap_menubar): Pop down menus that aren't the same as in old_stack. + Set width, heigh, x, y on widget with XtVaSetValues. Call + create_pixmap_for_menu. + Replace XUnmapWindow with XtPopdown. + Remowe two last parameters to display_menu. + (map_event_to_widget_value, XlwMenuRedisplay, Key, Select) + (pop_up_menu): Remowe two last parameters to display_menu. + (XlwMenuRealize): Call create_pixmap_for_menu, set w and pixmap. + Remove call to XftDrawCreate. + (XlwMenuDestroy): Free pixmap. Call XtDestroyWidget instead of + XDestroyWindow. + (handle_motion_event): Only call handle_single_motion_event once. + + * xlwmenuP.h (window_state): Add pixmap and w. + 2010-04-16 YAMAMOTO Mitsuharu * xlwmenu.c (facename_changed): Put function in #ifdef HAVE_XFT. diff -r 1da056389889 -r 9a798edc503b lwlib/xlwmenu.c --- a/lwlib/xlwmenu.c Sat Apr 17 11:53:55 2010 -0400 +++ b/lwlib/xlwmenu.c Sat Apr 17 19:43:03 2010 +0200 @@ -44,6 +44,7 @@ #include #include #include +#include #include "xlwmenuP.h" #ifdef emacs @@ -186,7 +187,6 @@ static Boolean XlwMenuSetValues(); static void XlwMenuRealize(); -static void XlwMenuRedisplay(); static void XlwMenuResize(); static void XlwMenuInitialize(); static void XlwMenuRedisplay(); @@ -1067,13 +1067,13 @@ if (separator_p) { - draw_separator (mw, ws->window, x, y, width, separator); + draw_separator (mw, ws->pixmap, x, y, width, separator); } else { int x_offset = x + h_spacing + shadow; char* display_string = resource_widget_value (mw, val); - draw_shadow_rectangle (mw, ws->window, x, y, width, height, True, + draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True, False); /* Deal with centering a menu title. */ @@ -1092,9 +1092,6 @@ if (ws->xft_draw) { int draw_y = y + v_spacing + shadow; - XftDrawRect (ws->xft_draw, &mw->menu.xft_bg, - x_offset, draw_y, - ws->width, font_height); XftDrawStringUtf8 (ws->xft_draw, xftfg, mw->menu.xft_font, x_offset, draw_y + font_ascent, @@ -1105,13 +1102,13 @@ #endif #ifdef HAVE_X_I18N if (mw->menu.fontSet) - XmbDrawString (XtDisplay (mw), ws->window, mw->menu.fontSet, + XmbDrawString (XtDisplay (mw), ws->pixmap, mw->menu.fontSet, text_gc, x_offset, y + v_spacing + shadow + font_ascent, display_string, strlen (display_string)); else #endif - XDrawString (XtDisplay (mw), ws->window, + XDrawString (XtDisplay (mw), ws->pixmap, text_gc, x_offset, y + v_spacing + shadow + font_ascent, display_string, strlen (display_string)); @@ -1119,16 +1116,16 @@ if (!horizontal_p) { if (val->button_type == BUTTON_TYPE_TOGGLE) - draw_toggle (mw, ws->window, x, y + v_spacing + shadow, + draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow, val->selected); else if (val->button_type == BUTTON_TYPE_RADIO) - draw_radio (mw, ws->window, x, y + v_spacing + shadow, + draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow, val->selected); if (val->contents) { int a_w = arrow_width (mw); - draw_arrow (mw, ws->window, deco_gc, + draw_arrow (mw, ws->pixmap, deco_gc, x + width - a_w - mw->menu.horizontal_spacing - mw->menu.shadow_thickness, @@ -1154,7 +1151,7 @@ #endif #ifdef HAVE_X_I18N if (mw->menu.fontSet) - XmbDrawString (XtDisplay (mw), ws->window, + XmbDrawString (XtDisplay (mw), ws->pixmap, mw->menu.fontSet, text_gc, x + label_width + mw->menu.arrow_spacing, @@ -1162,7 +1159,7 @@ val->key, strlen (val->key)); else #endif - XDrawString (XtDisplay (mw), ws->window, + XDrawString (XtDisplay (mw), ws->pixmap, text_gc, x + label_width + mw->menu.arrow_spacing, y + v_spacing + shadow + font_ascent, @@ -1171,17 +1168,17 @@ } else { - XDrawRectangle (XtDisplay (mw), ws->window, + XDrawRectangle (XtDisplay (mw), ws->pixmap, mw->menu.background_gc, x + shadow, y + shadow, label_width + h_spacing - 1, font_height + 2 * v_spacing - 1); - draw_shadow_rectangle (mw, ws->window, x, y, width, height, + draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True, False); } if (highlighted_p) - draw_shadow_rectangle (mw, ws->window, x, y, width, height, False, + draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False, False); } } @@ -1191,16 +1188,13 @@ } static void -display_menu (mw, level, just_compute_p, highlighted_pos, hit, hit_return, - this, that) +display_menu (mw, level, just_compute_p, highlighted_pos, hit, hit_return) XlwMenuWidget mw; int level; Boolean just_compute_p; XPoint* highlighted_pos; XPoint* hit; widget_value** hit_return; - widget_value* this; - widget_value* that; { widget_value* val; widget_value* following_item; @@ -1208,9 +1202,6 @@ XPoint where; int horizontal_p = mw->menu.horizontal && (level == 0); int highlighted_p; - int just_compute_this_one_p; - /* This is set nonzero if the element containing HIGHLIGHTED_POS - is disabled, so that we do not return any subsequent element either. */ int no_return = 0; enum menu_separator separator; @@ -1229,6 +1220,11 @@ where.y = 0; ws = &mw->menu.windows [level]; + + if (!just_compute_p) + XFillRectangle (XtDisplay (mw), ws->pixmap, mw->menu.background_gc, + 0, 0, ws->width, ws->height); + for (val = mw->menu.old_stack [level]->contents; val; val = val->next) { highlighted_p = val == following_item; @@ -1240,11 +1236,8 @@ highlighted_pos->y = where.y; } - just_compute_this_one_p = - just_compute_p || ((this || that) && val != this && val != that); - display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p, - just_compute_this_one_p); + just_compute_p); if (highlighted_p && highlighted_pos) { @@ -1282,8 +1275,12 @@ } if (!just_compute_p) - draw_shadow_rectangle (mw, ws->window, 0, 0, ws->width, ws->height, - False, False); + { + draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height, + False, False); + XCopyArea (XtDisplay (mw), ws->pixmap, ws->window, + mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0); + } } /* Motion code */ @@ -1302,15 +1299,28 @@ } static void +expose_cb (Widget widget, + XtPointer closure, + XEvent* event, + Boolean* continue_to_dispatch) +{ + *continue_to_dispatch = False; + XlwMenuWidget mw = (XlwMenuWidget) closure; + int i; + + for (i = 0; i < mw->menu.windows_length; ++i) + if (mw->menu.windows [i].w == widget) break; + if (i < mw->menu.windows_length && i < mw->menu.old_depth) + display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL); +} + +static void make_windows_if_needed (mw, n) XlwMenuWidget mw; int n; { int i; int start_at; - XSetWindowAttributes xswa; - int mask; - Window root = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw))); window_state* windows; #ifdef HAVE_XFT int screen = XScreenNumberOfScreen (mw->core.screen); @@ -1319,17 +1329,6 @@ if (mw->menu.windows_length >= n) return; - xswa.save_under = True; - xswa.override_redirect = True; - xswa.background_pixel = mw->core.background_pixel; - xswa.border_pixel = mw->core.border_pixel; - xswa.event_mask = - ExposureMask | PointerMotionMask | PointerMotionHintMask - | ButtonReleaseMask | ButtonPressMask; - xswa.cursor = mw->menu.cursor_shape; - mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel - | CWEventMask | CWCursor; - if (!mw->menu.windows) { mw->menu.windows = @@ -1349,23 +1348,29 @@ for (i = start_at; i < n; i++) { + Arg av[10]; + int ac = 0; windows [i].x = 0; windows [i].y = 0; windows [i].width = 1; windows [i].height = 1; windows [i].max_rest_width = 0; - windows [i].window = - XCreateWindow (XtDisplay (mw), root, 0, 0, 1, 1, - 0, 0, CopyFromParent, CopyFromParent, mask, &xswa); + XtSetArg (av[ac], XtNwidth, 1); ++ac; + XtSetArg (av[ac], XtNheight, 1); ++ac; + XtSetArg (av[ac], XtNsaveUnder, True); ++ac; + XtSetArg (av[ac], XtNbackground, mw->core.background_pixel); ++ac; + XtSetArg (av[ac], XtNborderColor, mw->core.border_pixel); ++ac; + XtSetArg (av[ac], XtNborderWidth, mw->core.border_width); ++ac; + XtSetArg (av[ac], XtNcursor, mw->menu.cursor_shape); ++ac; + windows [i].w = + XtCreatePopupShell ("sub", overrideShellWidgetClass, + (Widget) mw, av, ac); + XtRealizeWidget (windows [i].w); + XtAddEventHandler (windows [i].w, ExposureMask, False, expose_cb, mw); + windows [i].window = XtWindow (windows [i].w); + windows [i].pixmap = None; #ifdef HAVE_XFT - if (mw->menu.xft_font) - mw->menu.windows [i].xft_draw - = XftDrawCreate (XtDisplay (mw), - windows [i].window, - DefaultVisual (XtDisplay (mw), screen), - mw->core.colormap); - else - mw->menu.windows [i].xft_draw = 0; + windows [i].xft_draw = 0; #endif } } @@ -1445,6 +1450,33 @@ } } +static void +create_pixmap_for_menu (window_state* ws, XlwMenuWidget mw) +{ + if (ws->pixmap != None) + { + XFreePixmap (XtDisplay (ws->w), ws->pixmap); + ws->pixmap = None; + } + ws->pixmap = XCreatePixmap (XtDisplay (ws->w), ws->window, + ws->width, ws->height, + DefaultDepthOfScreen (XtScreen (ws->w))); +#ifdef HAVE_XFT + if (ws->xft_draw) + XftDrawDestroy (ws->xft_draw); + if (mw->menu.xft_font) + { + int screen = XScreenNumberOfScreen (mw->core.screen); + ws->xft_draw = XftDrawCreate (XtDisplay (ws->w), + ws->pixmap, + DefaultVisual (XtDisplay (ws->w), screen), + mw->core.colormap); + } + else + ws->xft_draw = 0; +#endif +} + /* Updates old_stack from new_stack and redisplays. */ static void remap_menubar (mw) @@ -1490,14 +1522,17 @@ /* updates old_state from new_state. It has to be done now because display_menu (called below) uses the old_stack to know what to display. */ for (i = last_same + 1; i < new_depth; i++) - old_stack [i] = new_stack [i]; + { + XtPopdown (mw->menu.windows [i].w); + old_stack [i] = new_stack [i]; + } mw->menu.old_depth = new_depth; /* refresh the last selection */ selection_position.x = 0; selection_position.y = 0; display_menu (mw, last_same, new_selection == old_selection, - &selection_position, NULL, NULL, old_selection, new_selection); + &selection_position, NULL, NULL); /* Now place the new menus. */ for (i = last_same + 1; i < new_depth && new_stack[i]->contents; i++) @@ -1524,17 +1559,17 @@ fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1); - XClearWindow (XtDisplay (mw), ws->window); - XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y, - ws->width, ws->height); - XMapRaised (XtDisplay (mw), ws->window); - display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL); + XtVaSetValues (ws->w, XtNwidth, ws->width, XtNheight, ws->height, + XtNx, ws->x, XtNy, ws->y, NULL); + create_pixmap_for_menu (ws, mw); + XtPopup (ws->w, XtGrabNone); + display_menu (mw, i, False, &selection_position, NULL, NULL); } /* unmap the menus that popped down */ for (i = new_depth - 1; i < old_depth; i++) if (i >= new_depth || (i > 0 && !new_stack[i]->contents)) - XUnmapWindow (XtDisplay (mw), windows[i].window); + XtPopdown (windows[i].w); } static Boolean @@ -1575,7 +1610,7 @@ if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos)) { inside = 1; - display_menu (mw, i, True, NULL, &relative_pos, val, NULL, NULL); + display_menu (mw, i, True, NULL, &relative_pos, val); if (*val) { @@ -1954,6 +1989,7 @@ mw->menu.windows [0].width = 0; mw->menu.windows [0].height = 0; mw->menu.windows [0].max_rest_width = 0; + mw->menu.windows [0].pixmap = None; #ifdef HAVE_XFT mw->menu.windows [0].xft_draw = 0; #endif @@ -1996,22 +2032,19 @@ x_uncatch_errors (); #endif + mw->menu.windows [0].w = w; mw->menu.windows [0].window = XtWindow (w); mw->menu.windows [0].x = w->core.x; mw->menu.windows [0].y = w->core.y; mw->menu.windows [0].width = w->core.width; mw->menu.windows [0].height = w->core.height; + create_pixmap_for_menu (&mw->menu.windows [0], mw); + #ifdef HAVE_XFT if (mw->menu.xft_font) { XColor colors[3]; - int screen = XScreenNumberOfScreen (mw->core.screen); - mw->menu.windows [0].xft_draw - = XftDrawCreate (XtDisplay (w), - mw->menu.windows [0].window, - DefaultVisual (XtDisplay (w), screen), - mw->core.colormap); colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground; colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel; colors[2].pixel = mw->menu.xft_disabled_fg.pixel @@ -2030,8 +2063,6 @@ mw->menu.xft_disabled_fg.color.green = colors[2].green; mw->menu.xft_disabled_fg.color.blue = colors[2].blue; } - else - mw->menu.windows [0].xft_draw = 0; #endif } @@ -2055,8 +2086,7 @@ submenu_destroyed = 0; } - for (i = 0; i < mw->menu.old_depth; i++) - display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL); + display_menu (mw, 0, False, NULL, NULL, NULL); } @@ -2121,10 +2151,14 @@ XftFontClose (XtDisplay (mw), mw->menu.xft_font); #endif + if (mw->menu.windows [0].pixmap != None) + XFreePixmap (XtDisplay (mw), mw->menu.windows [0].pixmap); /* start from 1 because the one in slot 0 is w->core.window */ for (i = 1; i < mw->menu.windows_length; i++) { - XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window); + if (mw->menu.windows [i].pixmap != None) + XFreePixmap (XtDisplay (mw), mw->menu.windows [i].pixmap); + XtDestroyWidget (mw->menu.windows [i].w); #ifdef HAVE_XFT if (mw->menu.windows [i].xft_draw) XftDrawDestroy (mw->menu.windows [i].xft_draw); @@ -2140,7 +2174,7 @@ facename_changed (XlwMenuWidget newmw, XlwMenuWidget oldmw) { - /* This will fore a new XftFont even if the same sting is set. + /* This will fore a new XftFont even if the same string is set. This is good, as rendering parameters may have changed and we just want to do a redisplay. */ return newmw->menu.faceName != oldmw->menu.faceName; @@ -2250,13 +2284,14 @@ /* Don't allow the popup menu to resize itself. */ mw->core.width = mw->menu.windows [0].width; mw->core.height = mw->menu.windows [0].height; - mw->core.parent->core.width = mw->core.width ; - mw->core.parent->core.height = mw->core.height ; + mw->core.parent->core.width = mw->core.width; + mw->core.parent->core.height = mw->core.height; } else { mw->menu.windows [0].width = mw->core.width; mw->menu.windows [0].height = mw->core.height; + create_pixmap_for_menu (&mw->menu.windows [0], mw); } } @@ -2287,8 +2322,7 @@ int x = ev->x_root; int y = ev->y_root; int state = ev->state; - - handle_single_motion_event (mw, ev); + XMotionEvent oldev = *ev; /* allow motion events to be generated again */ if (ev->is_hint @@ -2300,6 +2334,8 @@ && ev->state == state && (ev->x_root != x || ev->y_root != y)) handle_single_motion_event (mw, ev); + else + handle_single_motion_event (mw, &oldev); } static void @@ -2609,7 +2645,7 @@ else { XtRemoveGrab ((Widget) mw); - display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); + display_menu (mw, 0, False, NULL, NULL, NULL); } } @@ -2650,7 +2686,7 @@ else { XtRemoveGrab ((Widget) mw); - display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); + display_menu (mw, 0, False, NULL, NULL, NULL); } } @@ -2701,7 +2737,7 @@ XtConfigureWidget (XtParent ((Widget)mw), x, y, w, h, XtParent ((Widget)mw)->core.border_width); XtPopup (XtParent ((Widget)mw), XtGrabExclusive); - display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); + display_menu (mw, 0, False, NULL, NULL, NULL); mw->menu.windows [0].x = x + borderwidth; mw->menu.windows [0].y = y + borderwidth; mw->menu.top_depth = 1; /* Popup menus don't have a bar so top is 1 */ diff -r 1da056389889 -r 9a798edc503b lwlib/xlwmenuP.h --- a/lwlib/xlwmenuP.h Sat Apr 17 11:53:55 2010 -0400 +++ b/lwlib/xlwmenuP.h Sat Apr 17 19:43:03 2010 +0200 @@ -32,7 +32,9 @@ /* Elements in the stack arrays. */ typedef struct _window_state { + Widget w; Window window; + Pixmap pixmap; Position x; Position y; Dimension width;