GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with GNU Emacs; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* Created by devin@lucid.com */
#include <sys/types.h>
#include <X11/Xos.h>
#include <X11/IntrinsicP.h>
+#include <X11/ObjectP.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/bitmaps/gray>
static int pointer_grabbed;
static XEvent menu_post_event;
+XFontStruct *xlwmenu_default_font;
+
static char
xlwMenuTranslations [] =
-"<BtnDown>: start()\n\
-<Motion>: drag()\n\
-<BtnUp>: select()\n\
+"<BtnDown>: start()\n\
+<Motion>: drag()\n\
+<BtnUp>: select()\n\
+<Key>Shift_L: nothing()\n\
+<Key>Shift_R: nothing()\n\
+<Key>Meta_L: nothing()\n\
+<Key>Meta_R: nothing()\n\
+<Key>Control_L: nothing()\n\
+<Key>Control_R: nothing()\n\
+<Key>Hyper_L: nothing()\n\
+<Key>Hyper_R: nothing()\n\
+<Key>Super_L: nothing()\n\
+<Key>Super_R: nothing()\n\
+<Key>Alt_L: nothing()\n\
+<Key>Alt_R: nothing()\n\
+<Key>Caps_Lock: nothing()\n\
+<Key>Shift_Lock: nothing()\n\
+<KeyUp>Shift_L: nothing()\n\
+<KeyUp>Shift_R: nothing()\n\
+<KeyUp>Meta_L: nothing()\n\
+<KeyUp>Meta_R: nothing()\n\
+<KeyUp>Control_L: nothing()\n\
+<KeyUp>Control_R: nothing()\n\
+<KeyUp>Hyper_L: nothing()\n\
+<KeyUp>Hyper_R: nothing()\n\
+<KeyUp>Super_L: nothing()\n\
+<KeyUp>Super_R: nothing()\n\
+<KeyUp>Alt_L: nothing()\n\
+<KeyUp>Alt_R: nothing()\n\
+<KeyUp>Caps_Lock: nothing()\n\
+<KeyUp>Shift_Lock:nothing()\n\
+<Key>: key()\n\
+<KeyUp>: key()\n\
";
#define offset(field) XtOffset(XlwMenuWidget, field)
static void Start();
static void Drag();
static void Select();
+static void Key();
+static void Nothing();
static XtActionsRec
xlwMenuActionsList [] =
{"start", Start},
{"drag", Drag},
{"select", Select},
+ {"key", Key},
+ {"nothing", Nothing},
};
#define SuperClass ((CoreWidgetClass)&coreClassRec)
XlwMenuWidget mw;
int level;
{
- int label_width = 0;
+ unsigned int label_width = 0;
int rest_width = 0;
int max_rest_width = 0;
- int height = 0;
+ unsigned int height = 0;
int horizontal_p = mw->menu.horizontal && (level == 0);
widget_value* val;
window_state* ws;
width = ws->width - 2 * shadow;
}
+#if 0
/* see if it should be a button in the menubar */
button_p = horizontal_p && val->call_data;
+#endif
+ button_p = 0;
/* Only highlight an enabled item that has a callback. */
if (highlighted_p)
}
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);
- XDrawString (XtDisplay (mw), ws->window, text_gc,
- x + h_spacing + shadow,
+
+ /* Deal with centering a menu title. */
+ if (!horizontal_p && !val->contents && !val->call_data)
+ {
+ int l = string_width (mw, display_string);
+
+ if (width > l)
+ x_offset = (width - l) >> 1;
+ }
+ XDrawString (XtDisplay (mw), ws->window, text_gc, x_offset,
y + v_spacing + shadow + font_ascent,
display_string, strlen (display_string));
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;
if (level >= mw->menu.old_depth)
abort ();
if (hit
&& !*hit_return
&& (horizontal_p ? hit->x < where.x : hit->y < where.y)
- && !all_dashes_p (val->name))
- *hit_return = val;
+ && !all_dashes_p (val->name)
+ && !no_return)
+ {
+ if (val->enabled)
+ *hit_return = val;
+ else
+ no_return = 1;
+ }
if (horizontal_p)
where.y = 0;
window_state* previous_ws;
Boolean horizontal_p;
{
- int screen_width = WidthOfScreen (XtScreen (mw));
- int screen_height = HeightOfScreen (XtScreen (mw));
+ unsigned int screen_width = WidthOfScreen (XtScreen (mw));
+ unsigned int screen_height = HeightOfScreen (XtScreen (mw));
+ /* 1 if we are unable to avoid an overlap between
+ this menu and the parent menu in the X dimension. */
+ int horizontal_overlap = 0;
if (ws->x < 0)
ws->x = 0;
ws->x = previous_ws->x - ws->width;
else
ws->x = screen_width - ws->width;
+ if (ws->x < 0)
+ {
+ ws->x = 0;
+ horizontal_overlap = 1;
+ }
}
+ /* If we overlap in X, try to avoid overlap in Y. */
+ if (horizontal_overlap
+ && ws->y < previous_ws->y + previous_ws->height
+ && previous_ws->y < ws->y + ws->height)
+ {
+ /* Put this menu right below or right above PREVIOUS_WS
+ if there's room. */
+ if (previous_ws->y + previous_ws->height + ws->height < screen_height)
+ ws->y = previous_ws->y + previous_ws->height;
+ else if (previous_ws->y - ws->height > 0)
+ ws->y = previous_ws->y - ws->height;
+ }
+
if (ws->y < 0)
ws->y = 0;
else if (ws->y + ws->height > screen_height)
ws->y = previous_ws->y - ws->height;
else
ws->y = screen_height - ws->height;
+ if (ws->y < 0)
+ ws->y = 0;
}
}
old_stack [i] = new_stack [i];
mw->menu.old_depth = new_depth;
- /* refresh the last seletion */
+ /* 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);
- /* Now popup the new menus */
- for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++)
+ /* Now place the new menus. */
+ for (i = last_same + 1; i < new_depth && new_stack[i]->contents; i++)
{
- window_state* previous_ws = &windows [i - 1];
- window_state* ws = &windows [i];
+ window_state *previous_ws = &windows[i - 1];
+ window_state *ws = &windows[i];
- ws->x =
- previous_ws->x + selection_position.x + mw->menu.shadow_thickness;
+ ws->x
+ = previous_ws->x + selection_position.x + mw->menu.shadow_thickness;
if (!mw->menu.horizontal || i > 1)
ws->x += mw->menu.shadow_thickness;
- ws->y =
- previous_ws->y + selection_position.y + mw->menu.shadow_thickness;
+ ws->y
+ = previous_ws->y + selection_position.y + mw->menu.shadow_thickness;
size_menu (mw, i);
/* unmap the menus that popped down */
for (i = new_depth - 1; i < old_depth; i++)
- if (i >= new_depth || !new_stack [i]->contents)
- XUnmapWindow (XtDisplay (mw), windows [i].window);
+ if (i >= new_depth || !new_stack[i]->contents)
+ XUnmapWindow (XtDisplay (mw), windows[i].window);
}
static Boolean
XPoint* relative_pos;
{
window_state* ws = &mw->menu.windows [level];
- int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
- int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
+ int shadow = level == 0 ? 0 : mw->menu.shadow_thickness;
+ int x = ws->x + shadow;
+ int y = ws->y + shadow;
relative_pos->x = ev->x_root - x;
relative_pos->y = ev->y_root - y;
- return (x < ev->x_root && ev->x_root < x + ws->width
- && y < ev->y_root && ev->y_root < y + ws->height);
+ return (x - shadow < ev->x_root && ev->x_root < x + ws->width
+ && y - shadow < ev->y_root && ev->y_root < y + ws->height);
}
static Boolean
}
static void
-XlwMenuInitialize (request, new, args, num_args)
+XlwMenuInitialize (request, mw, args, num_args)
Widget request;
- Widget new;
+ XlwMenuWidget mw;
ArgList args;
Cardinal *num_args;
{
/* Get the GCs and the widget size */
- XlwMenuWidget mw = (XlwMenuWidget)new;
-
XSetWindowAttributes xswa;
int mask;
/* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
mw->menu.cursor = mw->menu.cursor_shape;
- mw->menu.gray_pixmap = XCreatePixmapFromBitmapData (display, window,
- gray_bits, gray_width,
- gray_height, 1, 0, 1);
+ mw->menu.gray_pixmap
+ = XCreatePixmapFromBitmapData (display, window, gray_bits,
+ gray_width, gray_height,
+ (unsigned long)1, (unsigned long)0, 1);
+ /* I don't understand why this ends up 0 sometimes,
+ but it does. This kludge works around it.
+ Can anyone find a real fix? -- rms. */
+ if (mw->menu.font == 0)
+ mw->menu.font = xlwmenu_default_font;
+
make_drawing_gcs (mw);
make_shadow_gcs (mw);
&& newmw->menu.contents->contents
&& newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
redisplay = True;
+ /* Do redisplay if the contents are entirely eliminated. */
+ if (newmw->menu.contents
+ && newmw->menu.contents->contents == 0
+ && newmw->menu.contents->change >= VISIBLE_CHANGE)
+ redisplay = True;
if (newmw->core.background_pixel != oldmw->core.background_pixel
|| newmw->menu.foreground != oldmw->menu.foreground
set_new_state (mw, val, level);
remap_menubar (mw);
-#if 0
/* Sync with the display. Makes it feel better on X terms. */
XSync (XtDisplay (mw), False);
-#endif
}
static void
if (!mw->menu.popped_up)
{
menu_post_event = *ev;
- next_release_must_exit = 0;
+ pop_up_menu (mw, ev);
}
else
- /* If we push a button while the menu is posted semipermanently,
- releasing the button should always pop the menu down. */
- next_release_must_exit = 1;
+ {
+ /* If we push a button while the menu is posted semipermanently,
+ releasing the button should always pop the menu down. */
+ next_release_must_exit = 1;
- XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
-
- /* notes the absolute position of the menubar window */
- mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
- mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
+ /* notes the absolute position of the menubar window */
+ mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
+ mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
- /* handles the down like a move, slots are compatible */
- handle_motion_event (mw, &ev->xmotion);
- XtGrabPointer ((Widget)mw, False,
- (PointerMotionMask | PointerMotionHintMask
- | ButtonReleaseMask | ButtonPressMask),
- GrabModeAsync, GrabModeAsync, None,
- mw->menu.cursor_shape,
- ((XButtonPressedEvent *)ev)->time);
- pointer_grabbed = 1;
+ /* handles the down like a move, slots are compatible */
+ handle_motion_event (mw, &ev->xmotion);
+ }
}
static void
Cardinal *num_params;
{
XlwMenuWidget mw = (XlwMenuWidget)w;
- handle_motion_event (mw, &ev->xmotion);
+ if (mw->menu.popped_up)
+ handle_motion_event (mw, &ev->xmotion);
}
-static void
+/* Do nothing.
+ This is how we handle presses and releases of modifier keys. */
+static void
+Nothing (w, ev, params, num_params)
+ Widget w;
+ XEvent *ev;
+ String *params;
+ Cardinal *num_params;
+{
+}
+
+/* Handle key press and release events while menu is popped up.
+ Our action is to get rid of the menu. */
+static void
+Key (w, ev, params, num_params)
+ Widget w;
+ XEvent *ev;
+ String *params;
+ Cardinal *num_params;
+{
+ XlwMenuWidget mw = (XlwMenuWidget)w;
+
+ /* Pop down everything. */
+ mw->menu.new_depth = 1;
+ remap_menubar (mw);
+
+ if (mw->menu.popped_up)
+ {
+ mw->menu.popped_up = False;
+ XtUngrabPointer ((Widget)mw, ev->xmotion.time);
+ if (XtIsShell (XtParent ((Widget) mw)))
+ XtPopdown (XtParent ((Widget) mw));
+ else
+ {
+ XtRemoveGrab ((Widget) mw);
+ display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+ }
+ }
+
+ /* callback */
+ XtCallCallbackList ((Widget)mw, mw->menu.select, (XtPointer)0);
+}
+
+static void
Select (w, ev, params, num_params)
Widget w;
XEvent *ev;
{
mw->menu.popped_up = False;
XtUngrabPointer ((Widget)mw, ev->xmotion.time);
- XtPopdown (XtParent (mw));
+ if (XtIsShell (XtParent ((Widget) mw)))
+ XtPopdown (XtParent ((Widget) mw));
+ else
+ {
+ XtRemoveGrab ((Widget) mw);
+ display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+ }
}
/* callback */
XtCallCallbackList ((Widget)mw, mw->menu.select, (XtPointer)selected_item);
-
}
int h;
int borderwidth = mw->menu.shadow_thickness;
Screen* screen = XtScreen (mw);
+ Display *display = XtDisplay (mw);
+ int count;
next_release_must_exit = 0;
XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
- size_menu (mw, 0);
+ if (XtIsShell (XtParent ((Widget)mw)))
+ size_menu (mw, 0);
w = mw->menu.windows [0].width;
h = mw->menu.windows [0].height;
y = HeightOfScreen (screen) - h - 2 * borderwidth;
mw->menu.popped_up = True;
- XtConfigureWidget (XtParent (mw), x, y, w, h,
- XtParent (mw)->core.border_width);
- XtPopup (XtParent (mw), XtGrabExclusive);
- display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
+ if (XtIsShell (XtParent ((Widget)mw)))
+ {
+ 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);
+ mw->menu.windows [0].x = x + borderwidth;
+ mw->menu.windows [0].y = y + borderwidth;
+ }
+ else
+ {
+ XEvent *ev = (XEvent *) event;
+
+ XtAddGrab ((Widget) mw, True, True);
+
+ /* notes the absolute position of the menubar window */
+ mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
+ mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
+ }
+
#ifdef emacs
- x_catch_errors ();
+ count = x_catch_errors (display);
#endif
XtGrabPointer ((Widget)mw, False,
- (PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask
+ (PointerMotionMask
+ | PointerMotionHintMask
+ | ButtonReleaseMask
| ButtonPressMask),
- GrabModeAsync, GrabModeAsync, None, mw->menu.cursor_shape,
+ GrabModeAsync, GrabModeAsync, None,
+ mw->menu.cursor_shape,
event->time);
pointer_grabbed = 1;
#ifdef emacs
- if (x_had_errors_p ())
+ if (x_had_errors_p (display))
{
pointer_grabbed = 0;
XtUngrabPointer ((Widget)mw, event->time);
}
- x_uncatch_errors ();
+ x_uncatch_errors (display, count);
#endif
- mw->menu.windows [0].x = x + borderwidth;
- mw->menu.windows [0].y = y + borderwidth;
-
handle_motion_event (mw, (XMotionEvent*)event);
}