summaryrefslogtreecommitdiff
path: root/lwlib
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /lwlib
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip
Merge 'master' into noverlay
Diffstat (limited to 'lwlib')
-rw-r--r--lwlib/ChangeLog.12
-rw-r--r--lwlib/Makefile.in25
-rw-r--r--lwlib/deps.mk2
-rw-r--r--lwlib/lwlib-Xaw.c97
-rw-r--r--lwlib/lwlib-Xaw.h6
-rw-r--r--lwlib/lwlib-Xlw.c2
-rw-r--r--lwlib/lwlib-Xlw.h6
-rw-r--r--lwlib/lwlib-Xm.c84
-rw-r--r--lwlib/lwlib-int.h5
-rw-r--r--lwlib/lwlib-utils.c154
-rw-r--r--lwlib/lwlib-utils.h45
-rw-r--r--lwlib/lwlib-widget.h2
-rw-r--r--lwlib/lwlib.c19
-rw-r--r--lwlib/lwlib.h8
-rw-r--r--lwlib/xlwmenu.c626
-rw-r--r--lwlib/xlwmenu.h8
-rw-r--r--lwlib/xlwmenuP.h31
17 files changed, 797 insertions, 325 deletions
diff --git a/lwlib/ChangeLog.1 b/lwlib/ChangeLog.1
index 623b798cc73..4dac7763b92 100644
--- a/lwlib/ChangeLog.1
+++ b/lwlib/ChangeLog.1
@@ -1964,7 +1964,7 @@
;; coding: utf-8
;; End:
- Copyright (C) 1995-1999, 2001-2017 Free Software Foundation, Inc.
+ Copyright (C) 1995-1999, 2001-2022 Free Software Foundation, Inc.
This file is part of GNU Emacs.
diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in
index 148002aaaee..d58c7bf6ac5 100644
--- a/lwlib/Makefile.in
+++ b/lwlib/Makefile.in
@@ -1,7 +1,7 @@
### @configure_input@
# Copyright (C) 1992, 1993 Lucid, Inc.
-# Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
+# Copyright (C) 1994, 2001-2022 Free Software Foundation, Inc.
#
# This file is part of the Lucid Widget Library.
#
@@ -26,6 +26,7 @@ all: liblw.a
.PHONY: all
srcdir=@srcdir@
+top_builddir=@top_builddir@
# MinGW CPPFLAGS may use this.
abs_top_srcdir=@abs_top_srcdir@
VPATH=@srcdir@
@@ -56,23 +57,7 @@ TOOLKIT_OBJS = $(@X_TOOLKIT_TYPE@_OBJS)
OBJS = lwlib.o $(TOOLKIT_OBJS) lwlib-utils.o
-# 'make' verbosity.
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-
-AM_V_CC = $(am__v_CC_@AM_V@)
-am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
-am__v_CC_0 = @echo " CC " $@;
-am__v_CC_1 =
-
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo " GEN " $@;
-am__v_GEN_1 =
-
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 =
+-include ${top_builddir}/src/verbose.mk
AUTO_DEPEND = @AUTO_DEPEND@
DEPDIR = deps
@@ -111,7 +96,7 @@ $(globals_h):
.PHONY: mostlyclean clean distclean bootstrap-clean maintainer-clean
clean mostlyclean:
- rm -f *.o liblw.a \#* $(DEPDIR)/*
+ rm -f ./*.o liblw.a \#* $(DEPDIR)/*
distclean: clean
rm -f Makefile
@@ -131,6 +116,6 @@ FORCE:
.PHONY: tags FORCE
tags: TAGS
TAGS: ${ETAGS} $(ctagsfiles)
- ${ETAGS} $(ctagsfiles)
+ $(AM_V_GEN)${ETAGS} $(ctagsfiles)
### Makefile.in ends here
diff --git a/lwlib/deps.mk b/lwlib/deps.mk
index 5bdf1af7788..6a7eb1e0cab 100644
--- a/lwlib/deps.mk
+++ b/lwlib/deps.mk
@@ -1,7 +1,7 @@
### deps.mk --- lwlib/Makefile fragment for GNU Emacs
# Copyright (C) 1992, 1993 Lucid, Inc.
-# Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
+# Copyright (C) 1994, 2001-2022 Free Software Foundation, Inc.
#
# This file is part of the Lucid Widget Library.
#
diff --git a/lwlib/lwlib-Xaw.c b/lwlib/lwlib-Xaw.c
index ce007ae8b0b..b09795ec38c 100644
--- a/lwlib/lwlib-Xaw.c
+++ b/lwlib/lwlib-Xaw.c
@@ -1,7 +1,7 @@
/* The lwlib interface to Athena widgets.
Copyright (C) 1993 Chuck Thompson <cthomp@cs.uiuc.edu>
-Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
+Copyright (C) 1994, 2001-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -50,8 +50,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <X11/Xatom.h>
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
+#ifdef USE_CAIRO
+#include <stdlib.h>
+#include "lwlib-utils.h"
+#else /* HAVE_XFT */
#include <X11/Xft/Xft.h>
+#endif
struct widget_xft_data
{
@@ -79,7 +84,7 @@ lw_xaw_widget_p (Widget widget)
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
static void
fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font)
{
@@ -113,6 +118,23 @@ fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font)
data->p_width = data->p_height = 0;
}
+static void
+destroy_xft_data (Widget widget, XtPointer closure, XtPointer call_data)
+{
+ struct widget_xft_data *xft_data = closure;
+
+ for (int i = 0; xft_data[i].widget; ++i)
+ {
+ if (xft_data[i].xft_draw)
+ XftDrawDestroy (xft_data[i].xft_draw);
+ if (xft_data[i].p != None)
+ XFreePixmap (XtDisplay (widget), xft_data[i].p);
+ }
+ if (xft_data[0].xft_font)
+ XftFontClose (XtDisplay (widget), xft_data[0].xft_font);
+ xfree (xft_data);
+}
+
static XftFont*
openFont (Widget widget, char *name)
{
@@ -154,7 +176,7 @@ get_text_width_and_height (Widget widget, char *text,
&gi);
bp = cp ? cp + 1 : NULL;
h += xft_font->height;
- if (w < gi.width) w = gi.width;
+ if (w < gi.xOff) w = gi.xOff;
}
*height = h;
@@ -170,11 +192,12 @@ draw_text (struct widget_xft_data *data, char *lbl, int inverse)
int x = inverse ? 0 : 2;
char *bp = lbl;
- data->xft_draw = XftDrawCreate (XtDisplay (data->widget),
- data->p,
- DefaultVisual (XtDisplay (data->widget),
- screen),
- DefaultColormapOfScreen (sc));
+ if (!data->xft_draw)
+ data->xft_draw = XftDrawCreate (XtDisplay (data->widget),
+ data->p,
+ DefaultVisual (XtDisplay (data->widget),
+ screen),
+ DefaultColormapOfScreen (sc));
XftDrawRect (data->xft_draw,
inverse ? &data->xft_fg : &data->xft_bg,
0, 0, data->p_width, data->p_height);
@@ -192,6 +215,9 @@ draw_text (struct widget_xft_data *data, char *lbl, int inverse)
/* 1.2 gives reasonable line spacing. */
y += data->xft_font->height * 1.2;
}
+#ifdef USE_CAIRO
+ cairo_surface_flush (cairo_get_target (data->xft_draw));
+#endif
}
@@ -229,7 +255,7 @@ find_xft_data (Widget widget)
}
if (!inst || !inst->xft_data || !inst->xft_data[0].xft_font) return 0;
- for (nr = 0; data == NULL && nr < inst->nr_xft_data; ++nr)
+ for (nr = 0; data == NULL && inst->xft_data[nr].widget; ++nr)
{
if (inst->xft_data[nr].widget == widget)
data = &inst->xft_data[nr];
@@ -289,7 +315,7 @@ xaw_update_one_widget (widget_instance *instance,
if (XtIsSubclass (widget, dialogWidgetClass))
{
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (instance->xft_data && instance->xft_data[0].xft_font)
{
set_text (&instance->xft_data[0], instance->parent,
@@ -321,15 +347,15 @@ xaw_update_one_widget (widget_instance *instance,
XtSetArg (al[ac], XtNlabel, val->value);ac++;
/* Force centered button text. Se above. */
XtSetArg (al[ac], XtNjustify, XtJustifyCenter);ac++;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (instance->xft_data && instance->xft_data[0].xft_font)
{
int th;
int nr;
- for (nr = 0; nr < instance->nr_xft_data; ++nr)
+ for (nr = 0; instance->xft_data[nr].widget; ++nr)
if (instance->xft_data[nr].widget == widget)
break;
- if (nr < instance->nr_xft_data)
+ if (instance->xft_data[nr].widget)
{
set_text (&instance->xft_data[nr], instance->parent,
val->value, 6);
@@ -360,28 +386,6 @@ xaw_update_one_value (widget_instance *instance,
void
xaw_destroy_instance (widget_instance *instance)
{
-#ifdef HAVE_XFT
- if (instance->xft_data)
- {
- int i;
- for (i = 0; i < instance->nr_xft_data; ++i)
- {
- if (instance->xft_data[i].xft_draw)
- XftDrawDestroy (instance->xft_data[i].xft_draw);
- if (instance->xft_data[i].p != None)
- {
- XtVaSetValues (instance->xft_data[i].widget, XtNbitmap, None,
- NULL);
- XFreePixmap (XtDisplay (instance->widget),
- instance->xft_data[i].p);
- }
- }
- if (instance->xft_data[0].xft_font)
- XftFontClose (XtDisplay (instance->widget),
- instance->xft_data[0].xft_font);
- xfree (instance->xft_data);
- }
-#endif
if (XtIsSubclass (instance->widget, dialogWidgetClass))
/* Need to destroy the Shell too. */
XtDestroyWidget (XtParent (instance->widget));
@@ -477,7 +481,7 @@ static XtActionsRec xaw_actions [] = {
};
static Boolean actions_initted = False;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
static XtActionsRec button_actions[] =
{
{ "my_reset", command_reset },
@@ -510,7 +514,7 @@ make_dialog (char* name,
Widget dialog;
Widget button;
XtTranslations override;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
XftFont *xft_font = 0;
XtTranslations button_override;
#endif
@@ -525,7 +529,7 @@ make_dialog (char* name,
XtAppContext app = XtWidgetToApplicationContext (parent);
XtAppAddActions (app, xaw_actions,
sizeof (xaw_actions) / sizeof (xaw_actions[0]));
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
XtAppAddActions (app, button_actions,
sizeof (button_actions) / sizeof (button_actions[0]));
#endif
@@ -550,7 +554,7 @@ make_dialog (char* name,
override = XtParseTranslationTable (dialogOverride);
XtOverrideTranslations (dialog, override);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
{
int num;
Widget *ch = NULL;
@@ -568,7 +572,6 @@ make_dialog (char* name,
}
}
instance->xft_data = 0;
- instance->nr_xft_data = 0;
if (w)
{
XtResource rec[] =
@@ -588,11 +591,15 @@ make_dialog (char* name,
if (xft_font)
{
- instance->nr_xft_data = left_buttons + right_buttons + 1;
- instance->xft_data = calloc (instance->nr_xft_data,
+ int nr_xft_data = left_buttons + right_buttons + 1;
+ instance->xft_data = calloc (nr_xft_data + 1,
sizeof(*instance->xft_data));
+ if (!instance->xft_data)
+ memory_full ((nr_xft_data + 1) * sizeof *instance->xft_data);
fill_xft_data (&instance->xft_data[0], w, xft_font);
+ XtAddCallback (dialog, XtNdestroyCallback, destroy_xft_data,
+ instance->xft_data);
}
}
@@ -621,7 +628,7 @@ make_dialog (char* name,
sprintf (button_name, "button%d", ++bc);
button = XtCreateManagedWidget (button_name, commandWidgetClass,
dialog, av, ac);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (xft_font)
{
fill_xft_data (&instance->xft_data[bc], button, xft_font);
@@ -654,7 +661,7 @@ make_dialog (char* name,
sprintf (button_name, "button%d", ++bc);
button = XtCreateManagedWidget (button_name, commandWidgetClass,
dialog, av, ac);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (xft_font)
{
fill_xft_data (&instance->xft_data[bc], button, xft_font);
diff --git a/lwlib/lwlib-Xaw.h b/lwlib/lwlib-Xaw.h
index 363334b575e..644676f320d 100644
--- a/lwlib/lwlib-Xaw.h
+++ b/lwlib/lwlib-Xaw.h
@@ -15,15 +15,13 @@ void
xaw_update_one_widget (widget_instance *, Widget, widget_value *, Boolean);
void
-xaw_update_one_value (widget_instance *, Widget, widget_value *)
- ATTRIBUTE_CONST;
+xaw_update_one_value (widget_instance *, Widget, widget_value *);
void
xaw_destroy_instance (widget_instance *);
void
-xaw_popup_menu (Widget, XEvent *)
- ATTRIBUTE_CONST;
+xaw_popup_menu (Widget, XEvent *);
void
xaw_pop_instance (widget_instance *, Boolean);
diff --git a/lwlib/lwlib-Xlw.c b/lwlib/lwlib-Xlw.c
index 0d58a030ac0..e3b596369eb 100644
--- a/lwlib/lwlib-Xlw.c
+++ b/lwlib/lwlib-Xlw.c
@@ -1,7 +1,7 @@
/* The lwlib interface to "xlwmenu" menus.
Copyright (C) 1992 Lucid, Inc.
-Copyright (C) 1994, 2000-2017 Free Software Foundation, Inc.
+Copyright (C) 1994, 2000-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
diff --git a/lwlib/lwlib-Xlw.h b/lwlib/lwlib-Xlw.h
index 2d38eb7be66..b0790dc3a59 100644
--- a/lwlib/lwlib-Xlw.h
+++ b/lwlib/lwlib-Xlw.h
@@ -15,15 +15,13 @@ xlw_update_one_widget (widget_instance* instance, Widget widget,
void
xlw_update_one_value (widget_instance* instance, Widget widget,
- widget_value* val)
- ATTRIBUTE_CONST;
+ widget_value* val);
void
xlw_destroy_instance (widget_instance* instance);
void
-xlw_pop_instance (widget_instance* instance, Boolean up)
- ATTRIBUTE_CONST;
+xlw_pop_instance (widget_instance* instance, Boolean up);
void
xlw_popup_menu (Widget widget, XEvent * event);
diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c
index 2ac543cad7c..52ea304f717 100644
--- a/lwlib/lwlib-Xm.c
+++ b/lwlib/lwlib-Xm.c
@@ -1,6 +1,6 @@
/* The lwlib interface to Motif widgets.
-Copyright (C) 1994-1997, 1999-2017 Free Software Foundation, Inc.
+Copyright (C) 1994-1997, 1999-2022 Free Software Foundation, Inc.
Copyright (C) 1992 Lucid, Inc.
This file is part of the Lucid Widget Library.
@@ -115,6 +115,7 @@ static void xm_generic_callback (Widget, XtPointer, XtPointer);
static void xm_nosel_callback (Widget, XtPointer, XtPointer);
static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
+static void xm_pop_up_callback (Widget, XtPointer, XtPointer);
static void xm_internal_update_other_instances (Widget, XtPointer,
XtPointer);
static void xm_arm_callback (Widget, XtPointer, XtPointer);
@@ -269,28 +270,23 @@ static void
xm_arm_callback (Widget w, XtPointer client_data, XtPointer call_data)
{
XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
- widget_value *wv = (widget_value *) client_data;
- widget_instance *instance;
-
- /* Get the id of the menu bar or popup menu this widget is in. */
- while (w != NULL)
- {
- if (XmIsRowColumn (w))
- {
- unsigned char type = 0xff;
-
- XtVaGetValues (w, XmNrowColumnType, &type, NULL);
- if (type == XmMENU_BAR || type == XmMENU_POPUP)
- break;
- }
+ widget_value *wv = NULL;
+ widget_instance *instance = client_data;
+ XtPointer user_data;
+ Arg al[2];
+ int ac = 0;
- w = XtParent (w);
- }
+ XtSetArg (al[ac], XmNuserData, &user_data); ac++;
+ XtGetValues (w, al, ac);
+ wv = user_data;
- if (w != NULL)
+ if (wv != NULL)
{
- instance = lw_get_widget_instance (w);
- if (instance && instance->info->highlight_cb)
+ if (instance->info->highlight_cb
+ && (cbs->reason == XmCR_DISARM
+ || (cbs->event
+ && (cbs->event->type == EnterNotify
+ || cbs->event->type == MotionNotify))))
{
call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
instance->info->highlight_cb (w, instance->info->id, call_data);
@@ -501,9 +497,11 @@ make_menu_in_widget (widget_instance* instance,
;
children = (Widget*)(void*)XtMalloc (num_children * sizeof (Widget));
+#ifndef LESSTIF_VERSION
/* WIDGET should be a RowColumn. */
if (!XmIsRowColumn (widget))
emacs_abort ();
+#endif
/* Determine whether WIDGET is a menu bar. */
type = -1;
@@ -516,8 +514,12 @@ make_menu_in_widget (widget_instance* instance,
/* Add a callback to popups and pulldowns that is called when
it is made invisible again. */
if (!menubar_p)
- XtAddCallback (XtParent (widget), XmNpopdownCallback,
- xm_pop_down_callback, (XtPointer)instance);
+ {
+ XtAddCallback (XtParent (widget), XmNpopdownCallback,
+ xm_pop_down_callback, (XtPointer) instance);
+ XtAddCallback (XtParent (widget), XmNpopupCallback,
+ xm_pop_up_callback, (XtPointer) instance);
+ }
/* Preserve the first KEEP_FIRST_CHILDREN old children. */
for (child_index = 0, cur = val; child_index < keep_first_children;
@@ -537,7 +539,7 @@ make_menu_in_widget (widget_instance* instance,
ac = 0;
XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
- XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
+ XtSetArg (al[ac], XmNuserData, cur); ac++;
if (instance->pop_up_p && !cur->contents && !cur->call_data
&& !lw_separator_p (cur->name, &separator, 1))
@@ -568,14 +570,18 @@ make_menu_in_widget (widget_instance* instance,
? XmN_OF_MANY : XmONE_OF_MANY));
++ac;
button = XmCreateToggleButton (widget, cur->name, al, ac);
- XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
- XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
+ XtAddCallback (button, XmNarmCallback, xm_arm_callback,
+ (XtPointer) instance);
+ XtAddCallback (button, XmNdisarmCallback, xm_arm_callback,
+ (XtPointer) instance);
}
else
{
button = XmCreatePushButton (widget, cur->name, al, ac);
- XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur);
- XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur);
+ XtAddCallback (button, XmNarmCallback, xm_arm_callback,
+ (XtPointer) instance);
+ XtAddCallback (button, XmNdisarmCallback, xm_arm_callback,
+ (XtPointer) instance);
}
xm_update_label (instance, button, cur);
@@ -642,7 +648,7 @@ update_one_menu_entry (widget_instance* instance,
/* update the sensitivity and userdata */
/* Common to all widget types */
XtSetSensitive (widget, val->enabled);
- XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
+ XtVaSetValues (widget, XmNuserData, val, NULL);
/* update the menu button as a label. */
if (val->this_one_change >= VISIBLE_CHANGE)
@@ -842,7 +848,7 @@ xm_update_one_widget (widget_instance* instance,
/* Common to all widget types */
XtSetSensitive (widget, val->enabled);
- XtVaSetValues (widget, XmNuserData, val->call_data, NULL);
+ XtVaSetValues (widget, XmNuserData, val, NULL);
/* Common to all label like widgets */
if (XtIsSubclass (widget, xmLabelWidgetClass))
@@ -1787,6 +1793,7 @@ do_call (Widget widget,
int ac;
XtPointer user_data;
widget_instance* instance = (widget_instance*)closure;
+ widget_value *wv;
Widget instance_widget;
LWLIB_ID id;
@@ -1804,17 +1811,18 @@ do_call (Widget widget,
user_data = NULL;
XtSetArg (al [ac], XmNuserData, &user_data); ac++;
XtGetValues (widget, al, ac);
+ wv = user_data;
switch (type)
{
case pre_activate:
if (instance->info->pre_activate_cb)
- instance->info->pre_activate_cb (widget, id, user_data);
+ instance->info->pre_activate_cb (widget, id, wv ? wv->call_data : NULL);
break;
case selection:
if (instance->info->selection_cb)
- instance->info->selection_cb (widget, id, user_data);
+ instance->info->selection_cb (widget, id, wv ? wv->call_data : NULL);
break;
case no_selection:
@@ -1824,7 +1832,7 @@ do_call (Widget widget,
case post_activate:
if (instance->info->post_activate_cb)
- instance->info->post_activate_cb (widget, id, user_data);
+ instance->info->post_activate_cb (widget, id, wv ? wv->call_data : NULL);
break;
default:
@@ -1912,6 +1920,18 @@ xm_pop_down_callback (Widget widget,
do_call (widget, closure, post_activate);
}
+static void
+xm_pop_up_callback (Widget widget,
+ XtPointer closure,
+ XtPointer call_data)
+{
+ widget_instance *instance = (widget_instance *) closure;
+
+ if ((!instance->pop_up_p && XtParent (widget) == instance->widget)
+ || XtParent (widget) == instance->parent)
+ do_call (widget, closure, pre_activate);
+}
+
/* set the keyboard focus */
void
diff --git a/lwlib/lwlib-int.h b/lwlib/lwlib-int.h
index ae195a39a8f..100e2ece698 100644
--- a/lwlib/lwlib-int.h
+++ b/lwlib/lwlib-int.h
@@ -1,6 +1,6 @@
/*
Copyright (C) 1992 Lucid, Inc.
-Copyright (C) 2000-2017 Free Software Foundation, Inc.
+Copyright (C) 2000-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -30,9 +30,8 @@ typedef struct _widget_instance
Widget widget;
Widget parent;
Boolean pop_up_p;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
struct widget_xft_data *xft_data;
- int nr_xft_data;
#endif
struct _widget_info* info;
struct _widget_instance* next;
diff --git a/lwlib/lwlib-utils.c b/lwlib/lwlib-utils.c
index 6f33e510f71..ff86886c955 100644
--- a/lwlib/lwlib-utils.c
+++ b/lwlib/lwlib-utils.c
@@ -1,7 +1,7 @@
/* Defines some widget utility functions.
Copyright (C) 1992 Lucid, Inc.
-Copyright (C) 1994, 2001-2017 Free Software Foundation, Inc.
+Copyright (C) 1994, 2001-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -137,3 +137,155 @@ XtWidgetBeingDestroyedP (Widget widget)
{
return widget->core.being_destroyed;
}
+
+#ifdef USE_CAIRO
+/* Xft emulation on cairo. */
+#include <math.h>
+#include <cairo-ft.h>
+#include <cairo-xlib.h>
+
+XftFont *
+crxft_font_open_name (Display *dpy, int screen, const char *name)
+{
+ XftFont *pub = NULL;
+ FcPattern *match = NULL;
+ FcPattern *pattern = FcNameParse ((FcChar8 *) name);
+ if (pattern)
+ {
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+ double dpi;
+ if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) == FcResultNoMatch)
+ {
+ char *v = XGetDefault (dpy, "Xft", FC_DPI);
+ if (v == NULL || sscanf (v, "%lf", &dpi) != 1)
+ dpi = ((DisplayHeight (dpy, screen) * 25.4)
+ / DisplayHeightMM (dpy, screen));
+ FcPatternAddDouble (pattern, FC_DPI, dpi);
+ }
+ FcDefaultSubstitute (pattern);
+ FcResult result;
+ match = FcFontMatch (NULL, pattern, &result);
+ FcPatternDestroy (pattern);
+ }
+ if (match)
+ {
+ cairo_font_face_t *font_face
+ = cairo_ft_font_face_create_for_pattern (match);
+ if (font_face)
+ {
+ double pixel_size;
+ if ((FcPatternGetDouble (match, FC_PIXEL_SIZE, 0, &pixel_size)
+ != FcResultMatch)
+ || pixel_size < 1)
+ pixel_size = 10;
+
+ pub = xmalloc (sizeof (*pub));
+ cairo_matrix_t font_matrix, ctm;
+ cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
+ cairo_matrix_init_identity (&ctm);
+ cairo_font_options_t *options = cairo_font_options_create ();
+ cairo_ft_font_options_substitute (options, match);
+ pub->scaled_font = cairo_scaled_font_create (font_face, &font_matrix,
+ &ctm, options);
+ cairo_font_face_destroy (font_face);
+ cairo_font_options_destroy (options);
+
+ cairo_font_extents_t extents;
+ cairo_scaled_font_extents (pub->scaled_font, &extents);
+ pub->ascent = lround (extents.ascent);
+ pub->descent = lround (extents.descent);
+ pub->height = lround (extents.height);
+ pub->max_advance_width = lround (extents.max_x_advance);
+ }
+ FcPatternDestroy (match);
+ }
+ if (pub && pub->height <= 0)
+ {
+ crxft_font_close (pub);
+ pub = NULL;
+ }
+ return pub;
+}
+
+void
+crxft_font_close (XftFont *pub)
+{
+ cairo_scaled_font_destroy (pub->scaled_font);
+ xfree (pub);
+}
+
+cairo_t *
+crxft_draw_create (Display *dpy, Drawable drawable, Visual *visual)
+{
+ cairo_t *cr = NULL;
+ Window root;
+ int x, y;
+ unsigned int width, height, border_width, depth;
+
+ if (!XGetGeometry (dpy, drawable, &root, &x, &y, &width, &height,
+ &border_width, &depth))
+ return NULL;
+
+ cairo_surface_t *surface = cairo_xlib_surface_create (dpy, drawable, visual,
+ width, height);
+ if (surface)
+ {
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ return cr;
+}
+
+static void
+crxft_set_source_color (cairo_t *cr, const XftColor *color)
+{
+ cairo_set_source_rgba (cr, color->color.red / 65535.0,
+ color->color.green / 65535.0,
+ color->color.blue / 65535.0,
+ color->color.alpha / 65535.0);
+}
+
+void
+crxft_draw_rect (cairo_t *cr, const XftColor *color, int x, int y,
+ unsigned int width, unsigned int height)
+{
+ crxft_set_source_color (cr, color);
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_fill (cr);
+}
+
+void
+crxft_draw_string (cairo_t *cr, const XftColor *color, XftFont *pub,
+ int x, int y, const FcChar8 *string, int len)
+{
+ char *buf = xmalloc (len + 1);
+ memcpy (buf, string, len);
+ buf[len] = '\0';
+ crxft_set_source_color (cr, color);
+ cairo_set_scaled_font (cr, pub->scaled_font);
+ cairo_move_to (cr, x, y);
+ cairo_show_text (cr, buf);
+ xfree (buf);
+}
+
+void
+crxft_text_extents (XftFont *pub, const FcChar8 *string, int len,
+ XGlyphInfo *extents)
+{
+ char *buf = xmalloc (len + 1);
+ memcpy (buf, string, len);
+ buf[len] = '\0';
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_text_extents (pub->scaled_font, buf, &text_extents);
+ xfree (buf);
+ extents->x = ceil (- text_extents.x_bearing);
+ extents->y = ceil (- text_extents.y_bearing);
+ extents->width = (ceil (text_extents.x_bearing + text_extents.width)
+ + extents->x);
+ extents->height = (ceil (text_extents.y_bearing + text_extents.height)
+ + extents->y);
+ extents->xOff = lround (text_extents.x_advance);
+ extents->yOff = lround (text_extents.y_advance);
+}
+#endif /* USE_CAIRO */
diff --git a/lwlib/lwlib-utils.h b/lwlib/lwlib-utils.h
index ec3daab94ef..64372f19ad2 100644
--- a/lwlib/lwlib-utils.h
+++ b/lwlib/lwlib-utils.h
@@ -15,4 +15,49 @@ Widget *XtCompositeChildren (Widget, unsigned int *);
Boolean
XtWidgetBeingDestroyedP (Widget widget);
+#ifdef USE_CAIRO
+
+#include <cairo.h>
+#include <fontconfig/fontconfig.h>
+
+typedef struct {
+ cairo_scaled_font_t *scaled_font;
+ int ascent, descent, height, max_advance_width;
+} XftFont;
+
+typedef cairo_t XftDraw;
+
+typedef struct {
+ unsigned long pixel;
+ struct {unsigned short red, green, blue, alpha;} color;
+} XftColor;
+
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#else
+typedef struct {
+ unsigned short width, height;
+ short x, y, xOff, yOff;
+} XGlyphInfo;
+#endif
+
+#define XftFontOpenName crxft_font_open_name
+extern XftFont *crxft_font_open_name (Display *, int, const char *);
+#define XftFontClose(dpy, pub) crxft_font_close (pub)
+extern void crxft_font_close (XftFont *);
+#define XftDrawCreate(dpy, drawable, visual, colormap) \
+ crxft_draw_create (dpy, drawable, visual)
+extern cairo_t *crxft_draw_create (Display *, Drawable, Visual *);
+#define XftDrawDestroy cairo_destroy
+#define XftDrawRect crxft_draw_rect
+extern void crxft_draw_rect (cairo_t *, const XftColor *, int, int,
+ unsigned int, unsigned int);
+#define XftDrawStringUtf8 crxft_draw_string
+extern void crxft_draw_string (cairo_t *, const XftColor *, XftFont *,
+ int, int, const FcChar8 *, int);
+#define XftTextExtentsUtf8(dpy, pub, string, len, extents) \
+ crxft_text_extents (pub, string, len, extents)
+extern void crxft_text_extents (XftFont *, const FcChar8 *, int, XGlyphInfo *);
+
+#endif /* USE_CAIRO */
#endif /* _LWLIB_UTILS_H_ */
diff --git a/lwlib/lwlib-widget.h b/lwlib/lwlib-widget.h
index 6863b90c9ac..5226db5f63f 100644
--- a/lwlib/lwlib-widget.h
+++ b/lwlib/lwlib-widget.h
@@ -1,6 +1,6 @@
/*
Copyright (C) 1992, 1993 Lucid, Inc.
-Copyright (C) 1994, 1999-2017 Free Software Foundation, Inc.
+Copyright (C) 1994, 1999-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
diff --git a/lwlib/lwlib.c b/lwlib/lwlib.c
index 30fa046cb73..863f65c915f 100644
--- a/lwlib/lwlib.c
+++ b/lwlib/lwlib.c
@@ -1,7 +1,7 @@
/* A general interface to the widgets of different toolkits.
Copyright (C) 1992, 1993 Lucid, Inc.
-Copyright (C) 1994-1996, 1999-2017 Free Software Foundation, Inc.
+Copyright (C) 1994-1996, 1999-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -1233,8 +1233,7 @@ lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
{
int separator_p = 0;
- if (strlen (label) >= 3
- && memcmp (label, "--:", 3) == 0)
+ if (strncmp (label, "--:", 3) == 0)
{
static struct separator_table
{
@@ -1276,7 +1275,7 @@ lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
break;
}
}
- else if (strlen (label) > 3
+ else if (strnlen (label, 4) == 4
&& memcmp (label, "--", 2) == 0
&& label[2] != '-')
{
@@ -1325,10 +1324,14 @@ lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
{
/* Old-style separator, maybe. It's a separator if it contains
only dashes. */
- while (*label == '-')
- ++label;
- separator_p = *label == 0;
- *type = SEPARATOR_SHADOW_ETCHED_IN;
+ if (*label == '-')
+ {
+ while (*label == '-')
+ ++label;
+ separator_p = *label == 0;
+
+ *type = SEPARATOR_SHADOW_ETCHED_IN;
+ }
}
return separator_p;
diff --git a/lwlib/lwlib.h b/lwlib/lwlib.h
index e28d0e8356f..86b1c60a5de 100644
--- a/lwlib/lwlib.h
+++ b/lwlib/lwlib.h
@@ -1,6 +1,6 @@
/*
Copyright (C) 1992, 1993 Lucid, Inc.
-Copyright (C) 1994, 1999-2017 Free Software Foundation, Inc.
+Copyright (C) 1994, 1999-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -111,15 +111,9 @@ void lw_refigure_widget (Widget w, Boolean doit);
Boolean lw_window_is_in_menubar (Window win, Widget menubar_widget);
/* Manage resizing: TRUE permits resizing widget w; FALSE disallows it. */
-#ifndef USE_MOTIF
-ATTRIBUTE_CONST
-#endif
void lw_allow_resizing (Widget w, Boolean flag);
/* Set up the main window. */
-#ifndef USE_MOTIF
-ATTRIBUTE_CONST
-#endif
void lw_set_main_areas (Widget parent,
Widget menubar,
Widget work_area);
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index cfd20ba649e..deea50c8107 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -1,7 +1,7 @@
/* Implements a lightweight menubar widget.
Copyright (C) 1992 Lucid, Inc.
-Copyright (C) 1994-1995, 1997, 1999-2017 Free Software Foundation, Inc.
+Copyright (C) 1994-1995, 1997, 1999-2022 Free Software Foundation, Inc.
This file is part of the Lucid Widget Library.
@@ -48,6 +48,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#endif /* not emacs */
static int pointer_grabbed;
+static int keyboard_grabbed;
static XEvent menu_post_event;
static char
@@ -107,7 +108,7 @@ xlwMenuResources[] =
{XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet),
offset(menu.fontSet), XtRFontSet, NULL},
#endif
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
#define DEFAULT_FONTNAME "Sans-10"
#else
#define DEFAULT_FONTNAME "XtDefaultFont"
@@ -120,6 +121,10 @@ xlwMenuResources[] =
offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
{XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+ {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+ offset(menu.highlight_foreground), XtRImmediate, (XtPointer) -1},
+ {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+ offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
{XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
offset(menu.margin), XtRImmediate, (XtPointer)1},
{XtNhorizontalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
@@ -157,6 +162,9 @@ xlwMenuResources[] =
offset(menu.cursor_shape), XtRString, (XtPointer)"right_ptr"},
{XtNhorizontal, XtCHorizontal, XtRInt, sizeof(int),
offset(menu.horizontal), XtRImmediate, (XtPointer)True},
+ {XtNborderThickness, XtCBorderThickness, XtRDimension,
+ sizeof (Dimension), offset (menu.border_thickness),
+ XtRImmediate, (XtPointer)1}
};
#undef offset
@@ -242,11 +250,6 @@ WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec;
int submenu_destroyed;
-/* For debug, if installation-directory is non-nil this is not an installed
- Emacs. In that case we do not grab the keyboard to make it easier to
- debug. */
-#define GRAB_KEYBOARD (EQ (Vinstallation_directory, Qnil))
-
static int next_release_must_exit;
/* Utilities */
@@ -256,7 +259,9 @@ static void
ungrab_all (Widget w, Time ungrabtime)
{
XtUngrabPointer (w, ungrabtime);
- if (GRAB_KEYBOARD) XtUngrabKeyboard (w, ungrabtime);
+
+ if (keyboard_grabbed)
+ XtUngrabKeyboard (w, ungrabtime);
}
/* Like abort, but remove grabs from widget W before. */
@@ -325,14 +330,14 @@ string_width (XlwMenuWidget mw, char *s)
{
XCharStruct xcs;
int drop;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (mw->menu.xft_font)
{
XGlyphInfo gi;
XftTextExtentsUtf8 (XtDisplay (mw), mw->menu.xft_font,
(FcChar8 *) s,
strlen (s), &gi);
- return gi.width;
+ return gi.xOff;
}
#endif
#ifdef HAVE_X_I18N
@@ -349,7 +354,7 @@ string_width (XlwMenuWidget mw, char *s)
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
#define MENU_FONT_HEIGHT(mw) \
((mw)->menu.xft_font != NULL \
? (mw)->menu.xft_font->height \
@@ -569,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
int down_p)
{
Display *dpy = XtDisplay (mw);
- GC top_gc = mw->menu.shadow_top_gc;
- GC bottom_gc = mw->menu.shadow_bottom_gc;
+ GC top_gc, bottom_gc;
int thickness = mw->menu.shadow_thickness;
int height = width;
XPoint pt[10];
@@ -583,10 +587,13 @@ draw_arrow (XlwMenuWidget mw,
if (down_p)
{
- GC temp;
- temp = top_gc;
- top_gc = bottom_gc;
- bottom_gc = temp;
+ top_gc = mw->menu.highlight_shadow_bottom_gc;
+ bottom_gc = mw->menu.highlight_shadow_top_gc;
+ }
+ else
+ {
+ top_gc = mw->menu.shadow_top_gc;
+ bottom_gc = mw->menu.shadow_bottom_gc;
}
pt[0].x = x;
@@ -620,24 +627,49 @@ draw_arrow (XlwMenuWidget mw,
XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
}
-
-
+/* Generic draw shadow rectangle function. It is used to draw shadows
+ on menus, menu items and also toggle buttons. When ERASE_P is
+ true, it clears shadows. DOWN_P is true when a menu item is pushed
+ or a button toggled. TOP_GC and BOTTOM_GC are the graphic contexts
+ used to draw the top and bottom shadow respectively. */
static void
-draw_shadow_rectangle (XlwMenuWidget mw,
- Window window,
- int x,
- int y,
- int width,
- int height,
- int erase_p,
- int down_p)
+draw_shadow_rectangle (XlwMenuWidget mw, Window window, int x, int y,
+ int width, int height, int erase_p, int down_p,
+ GC top_gc, GC bottom_gc)
{
Display *dpy = XtDisplay (mw);
- GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
- GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
- int thickness = mw->menu.shadow_thickness;
+ int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
XPoint points [4];
+ /* Choose correct GC with a standard default if NULL. */
+ if (erase_p)
+ {
+ top_gc = mw->menu.background_gc;
+ bottom_gc = mw->menu.background_gc;
+ }
+ else
+ {
+ if (top_gc == NULL)
+ top_gc = mw->menu.shadow_top_gc;
+ if (bottom_gc == NULL)
+ bottom_gc = mw->menu.shadow_bottom_gc;
+ }
+
+ if (!erase_p && width == height && width == toggle_button_width (mw))
+ {
+ points [0].x = x;
+ points [0].y = y;
+ points [1].x = x + width;
+ points [1].y = y;
+ points [2].x = x + width;
+ points [2].y = y + height;
+ points [3].x = x;
+ points [3].y = y + height;
+ XFillPolygon (dpy, window,
+ down_p ? mw->menu.button_gc : mw->menu.inactive_button_gc,
+ points, 4, Convex, CoordModeOrigin);
+ }
+
if (!erase_p && down_p)
{
GC temp;
@@ -646,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
bottom_gc = temp;
}
+ /* Do draw (or erase) shadows */
points [0].x = x;
points [0].y = y;
points [1].x = x + width;
@@ -686,21 +719,43 @@ draw_shadow_rectangle (XlwMenuWidget mw,
static void
-draw_shadow_rhombus (XlwMenuWidget mw,
- Window window,
- int x,
- int y,
- int width,
- int height,
- int erase_p,
- int down_p)
+draw_shadow_rhombus (XlwMenuWidget mw, Window window, int x, int y,
+ int width, int height, int erase_p, int down_p,
+ GC top_gc, GC bottom_gc)
{
Display *dpy = XtDisplay (mw);
- GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
- GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
int thickness = mw->menu.shadow_thickness;
XPoint points [4];
+ /* Choose correct GC with a standard default if NULL */
+ if (erase_p)
+ {
+ top_gc = mw->menu.background_gc;
+ bottom_gc = mw->menu.background_gc;
+ }
+ else
+ {
+ if (top_gc == NULL)
+ top_gc = mw->menu.shadow_top_gc;
+ if (bottom_gc == NULL)
+ top_gc = mw->menu.shadow_bottom_gc;
+ }
+
+ if (!erase_p && width == height && width == radio_button_width (mw))
+ {
+ points [0].x = x;
+ points [0].y = y + width / 2;
+ points [1].x = x + height / 2;
+ points [1].y = y + width;
+ points [2].x = x + height;
+ points [2].y = y + width / 2;
+ points [3].x = x + height / 2;
+ points [3].y = y;
+ XFillPolygon (dpy, window,
+ down_p ? mw->menu.button_gc : mw->menu.inactive_button_gc,
+ points, 4, Convex, CoordModeOrigin);
+ }
+
if (!erase_p && down_p)
{
GC temp;
@@ -753,15 +808,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
toggle button is selected. */
static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+ int highlighted_p)
{
int width, height;
+ GC top_gc, bottom_gc;
+
+ if (highlighted_p)
+ {
+ top_gc = mw->menu.highlight_shadow_top_gc;
+ bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+ }
+ else
+ {
+ top_gc = mw->menu.shadow_top_gc;
+ bottom_gc = mw->menu.shadow_bottom_gc;
+ }
width = toggle_button_width (mw);
height = width;
x += mw->menu.horizontal_spacing;
y += (MENU_FONT_ASCENT (mw) - height) / 2;
- draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+ draw_shadow_rectangle (mw, window, x, y, width, height, False,
+ selected_p, top_gc, bottom_gc);
}
@@ -770,15 +839,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
toggle button is selected. */
static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+ int highlighted_p)
{
int width, height;
+ GC top_gc, bottom_gc;
+
+ if (highlighted_p)
+ {
+ top_gc = mw->menu.highlight_shadow_top_gc;
+ bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+ }
+ else
+ {
+ top_gc = mw->menu.shadow_top_gc;
+ bottom_gc = mw->menu.shadow_bottom_gc;
+ }
width = radio_button_width (mw);
height = width;
x += mw->menu.horizontal_spacing;
y += (MENU_FONT_ASCENT (mw) - height) / 2;
- draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+ draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+ top_gc, bottom_gc);
}
@@ -937,6 +1020,31 @@ separator_height (enum menu_separator separator)
}
}
+/* Draw the highlighted background and shadows. */
+
+static void
+draw_highlight (XlwMenuWidget mw, Window window, int x, int y, int width,
+ int height)
+{
+ Display *dpy = XtDisplay (mw);
+ XPoint points [4];
+
+ points [0].x = x;
+ points [0].y = y;
+ points [1].x = x + width;
+ points [1].y = y;
+ points [2].x = x + width;
+ points [2].y = y + height;
+ points [3].x = x;
+ points [3].y = y + height;
+ XFillPolygon (dpy, window,
+ mw->menu.highlight_background_gc,
+ points, 4, Convex, CoordModeOrigin);
+
+ draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+ mw->menu.highlight_shadow_top_gc,
+ mw->menu.highlight_shadow_bottom_gc);
+}
/* Display the menu item and increment where.x and where.y to show how large
the menu item was. */
@@ -952,7 +1060,6 @@ display_menu_item (XlwMenuWidget mw,
{
GC deco_gc;
GC text_gc;
- int font_height = MENU_FONT_HEIGHT (mw);
int font_ascent = MENU_FONT_ASCENT (mw);
int shadow = mw->menu.shadow_thickness;
int margin = mw->menu.margin;
@@ -965,7 +1072,7 @@ display_menu_item (XlwMenuWidget mw,
int width;
enum menu_separator separator;
int separator_p = lw_separator_p (val->name, &separator, 0);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
XftColor *xftfg;
#endif
@@ -1001,24 +1108,34 @@ display_menu_item (XlwMenuWidget mw,
/* pick the foreground and background GC. */
if (val->enabled)
- text_gc = mw->menu.foreground_gc;
+ if (highlighted_p)
+ text_gc = mw->menu.highlight_foreground_gc;
+ else
+ text_gc = mw->menu.foreground_gc;
else
text_gc = mw->menu.disabled_gc;
deco_gc = mw->menu.foreground_gc;
-#ifdef HAVE_XFT
- xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+#if defined USE_CAIRO || defined HAVE_XFT
+ if (val->enabled)
+ if (highlighted_p)
+ xftfg = &mw->menu.xft_highlight_fg;
+ else
+ xftfg = &mw->menu.xft_fg;
+ else
+ xftfg = &mw->menu.xft_disabled_fg;
#endif
if (separator_p)
- {
- draw_separator (mw, ws->pixmap, 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->pixmap, x, y, width, height, True,
- False);
+ /* Clears shadows and maybe highlight */
+ draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+ True, False, NULL, NULL);
+ if (highlighted_p)
+ draw_highlight (mw, ws->pixmap, x, y, width, height);
/* Deal with centering a menu title. */
if (!horizontal_p && !val->contents && !val->call_data)
@@ -1032,10 +1149,13 @@ display_menu_item (XlwMenuWidget mw,
x_offset += ws->button_width;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (ws->xft_draw)
{
int draw_y = y + v_spacing + shadow;
+#ifdef USE_CAIRO
+ cairo_surface_mark_dirty (cairo_get_target (ws->xft_draw));
+#endif
XftDrawStringUtf8 (ws->xft_draw, xftfg,
mw->menu.xft_font,
x_offset, draw_y + font_ascent,
@@ -1061,10 +1181,10 @@ display_menu_item (XlwMenuWidget mw,
{
if (val->button_type == BUTTON_TYPE_TOGGLE)
draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
- val->selected);
+ val->selected, highlighted_p);
else if (val->button_type == BUTTON_TYPE_RADIO)
draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
- val->selected);
+ val->selected, highlighted_p);
if (val->contents)
{
@@ -1078,7 +1198,7 @@ display_menu_item (XlwMenuWidget mw,
}
else if (val->key)
{
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (ws->xft_draw)
{
int draw_x = ws->width - ws->max_rest_width
@@ -1111,21 +1231,18 @@ display_menu_item (XlwMenuWidget mw,
}
else
{
- 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->pixmap, x, y, width, height,
- True, False);
+ /* If not highlighted, clears shadows for horizontal
+ menu item */
+ if (!highlighted_p)
+ draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+ True, False, NULL, NULL);
}
-
- if (highlighted_p)
- draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
- False);
+#ifdef USE_CAIRO
+ if (ws->xft_draw)
+ cairo_surface_flush (cairo_get_target (ws->xft_draw));
+#endif
}
}
-
where->x += width;
where->y += height;
}
@@ -1219,7 +1336,7 @@ display_menu (XlwMenuWidget mw,
if (!just_compute_p)
{
draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
- False, False);
+ False, False, NULL, NULL);
XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
}
@@ -1320,7 +1437,7 @@ make_windows_if_needed (XlwMenuWidget mw, int n)
XtAddEventHandler (windows [i].w, ExposureMask, False, expose_cb, mw);
windows [i].window = XtWindow (windows [i].w);
windows [i].pixmap = None;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
windows [i].xft_draw = 0;
#endif
set_window_type (windows [i].w, mw);
@@ -1350,27 +1467,46 @@ fit_to_screen (XlwMenuWidget mw,
window_state *previous_ws,
Boolean horizontal_p)
{
- unsigned int screen_width = WidthOfScreen (XtScreen (mw));
- unsigned int screen_height = HeightOfScreen (XtScreen (mw));
+ int screen_width, screen_height;
+ int screen_x, screen_y;
+ int prev_screen_x, prev_screen_y;
+
+#ifdef emacs
+ xlw_monitor_dimensions_at_pos (XtDisplay (mw), XtScreen (mw),
+ previous_ws->x, previous_ws->y,
+ &prev_screen_x, &prev_screen_y,
+ &screen_width, &screen_height);
+ xlw_monitor_dimensions_at_pos (XtDisplay (mw), XtScreen (mw),
+ ws->x, ws->y, &screen_x, &screen_y,
+ &screen_width, &screen_height);
+#else
+ screen_width = WidthOfScreen (XtScreen (mw));
+ screen_height = HeightOfScreen (XtScreen (mw));
+ prev_screen_x = screen_x = 0;
+ prev_screen_y = screen_y = 0;
+#endif
/* 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;
- else if (ws->x + ws->width > screen_width)
+ if (ws->x < screen_x)
+ ws->x = screen_x;
+ else if (ws->x + ws->width > screen_x + screen_width)
{
if (!horizontal_p)
/* The addition of shadow-thickness for a sub-menu's position is
to reflect a similar adjustment when the menu is displayed to
the right of the invoking menu-item; it makes the sub-menu
look more `attached' to the menu-item. */
- ws->x = previous_ws->x - ws->width + mw->menu.shadow_thickness;
+ ws->x = screen_x + (previous_ws->x
+ - prev_screen_x
+ - ws->width
+ + mw->menu.shadow_thickness);
else
- ws->x = screen_width - ws->width;
- if (ws->x < 0)
+ ws->x = screen_x + (screen_width - ws->width);
+ if (ws->x < screen_x)
{
- ws->x = 0;
+ ws->x = screen_x;
horizontal_overlap = 1;
}
}
@@ -1387,16 +1523,18 @@ fit_to_screen (XlwMenuWidget mw,
ws->y = previous_ws->y - ws->height;
}
- if (ws->y < 0)
- ws->y = 0;
- else if (ws->y + ws->height > screen_height)
+ if (ws->y < screen_y)
+ ws->y = screen_y;
+ else if (ws->y + ws->height > screen_y + screen_height)
{
if (horizontal_p)
- ws->y = previous_ws->y - ws->height;
+ ws->y = screen_y + (previous_ws->y
+ - prev_screen_y
+ - ws->height);
else
- ws->y = screen_height - ws->height;
- if (ws->y < 0)
- ws->y = 0;
+ ws->y = screen_y + (screen_height - ws->height);
+ if (ws->y < screen_y)
+ ws->y = screen_y;
}
}
@@ -1411,7 +1549,7 @@ create_pixmap_for_menu (window_state* ws, XlwMenuWidget mw)
ws->pixmap = XCreatePixmap (XtDisplay (ws->w), ws->window,
ws->width, ws->height,
DefaultDepthOfScreen (XtScreen (ws->w)));
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (ws->xft_draw)
XftDrawDestroy (ws->xft_draw);
if (mw->menu.xft_font)
@@ -1584,7 +1722,7 @@ map_event_to_widget_value (XlwMenuWidget mw,
return False;
}
- /* Procedures */
+
static void
make_drawing_gcs (XlwMenuWidget mw)
{
@@ -1617,7 +1755,6 @@ make_drawing_gcs (XlwMenuWidget mw)
#define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color) >> 16) & 0xff))
/* Allocate color for disabled menu-items. */
- mw->menu.disabled_foreground = mw->menu.foreground;
if (BRIGHTNESS(mw->menu.foreground) < BRIGHTNESS(mw->core.background_pixel))
scale = 2.3;
else
@@ -1656,6 +1793,20 @@ make_drawing_gcs (XlwMenuWidget mw)
xgcv.foreground = mw->core.background_pixel;
xgcv.background = mw->menu.foreground;
mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+ xgcv.foreground = ((mw->menu.highlight_foreground == -1)
+ ? mw->menu.foreground
+ : mw->menu.highlight_foreground);
+ xgcv.background = ((mw->menu.highlight_background == -1)
+ ? mw->core.background_pixel
+ : mw->menu.highlight_background);
+ mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+ xgcv.foreground = ((mw->menu.highlight_background == -1)
+ ? mw->core.background_pixel
+ : mw->menu.highlight_background);
+ xgcv.background = mw->menu.foreground;
+ mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
}
static void
@@ -1666,12 +1817,16 @@ release_drawing_gcs (XlwMenuWidget mw)
XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
/* let's get some segvs if we try to use these... */
mw->menu.foreground_gc = (GC) -1;
mw->menu.button_gc = (GC) -1;
mw->menu.disabled_gc = (GC) -1;
mw->menu.inactive_button_gc = (GC) -1;
mw->menu.background_gc = (GC) -1;
+ mw->menu.highlight_foreground_gc = (GC) -1;
+ mw->menu.highlight_background_gc = (GC) -1;
}
#ifndef emacs
@@ -1680,33 +1835,29 @@ release_drawing_gcs (XlwMenuWidget mw)
#endif
static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw, Pixel *top_color, Pixel *bottom_color,
+ Boolean *free_top_p, Boolean *free_bottom_p,
+ Pixmap *top_pixmap, Pixmap *bottom_pixmap,
+ Pixel fore_color, Pixel back_color)
{
- XGCValues xgcv;
- unsigned long pm = 0;
Display *dpy = XtDisplay ((Widget) mw);
Screen *screen = XtScreen ((Widget) mw);
Colormap cmap = mw->core.colormap;
XColor topc, botc;
int top_frobbed = 0, bottom_frobbed = 0;
- mw->menu.free_top_shadow_color_p = 0;
- mw->menu.free_bottom_shadow_color_p = 0;
+ *free_top_p = False;
+ *free_bottom_p = False;
- if (mw->menu.top_shadow_color == -1)
- mw->menu.top_shadow_color = mw->core.background_pixel;
- else
- mw->menu.top_shadow_color = mw->menu.top_shadow_color;
+ if (*top_color == -1)
+ *top_color = back_color;
- if (mw->menu.bottom_shadow_color == -1)
- mw->menu.bottom_shadow_color = mw->menu.foreground;
- else
- mw->menu.bottom_shadow_color = mw->menu.bottom_shadow_color;
+ if (*bottom_color == -1)
+ *bottom_color = fore_color;
- if (mw->menu.top_shadow_color == mw->core.background_pixel ||
- mw->menu.top_shadow_color == mw->menu.foreground)
+ if (*top_color == back_color || *top_color == fore_color)
{
- topc.pixel = mw->core.background_pixel;
+ topc.pixel = back_color;
#ifdef emacs
if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
&topc.pixel,
@@ -1720,15 +1871,14 @@ make_shadow_gcs (XlwMenuWidget mw)
if (XAllocColor (dpy, cmap, &topc))
#endif
{
- mw->menu.top_shadow_color = topc.pixel;
- mw->menu.free_top_shadow_color_p = 1;
+ *top_color = topc.pixel;
+ *free_top_p = True;
top_frobbed = 1;
}
}
- if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
- mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ if (*bottom_color == fore_color || *bottom_color == back_color)
{
- botc.pixel = mw->core.background_pixel;
+ botc.pixel = back_color;
#ifdef emacs
if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
&botc.pixel,
@@ -1741,8 +1891,8 @@ make_shadow_gcs (XlwMenuWidget mw)
if (XAllocColor (dpy, cmap, &botc))
#endif
{
- mw->menu.bottom_shadow_color = botc.pixel;
- mw->menu.free_bottom_shadow_color_p = 1;
+ *bottom_color = botc.pixel;
+ *free_bottom_p = True;
bottom_frobbed = 1;
}
}
@@ -1751,87 +1901,128 @@ make_shadow_gcs (XlwMenuWidget mw)
{
if (topc.pixel == botc.pixel)
{
- if (botc.pixel == mw->menu.foreground)
+ if (botc.pixel == fore_color)
{
- if (mw->menu.free_top_shadow_color_p)
+ if (*free_top_p)
{
- x_free_dpy_colors (dpy, screen, cmap,
- &mw->menu.top_shadow_color, 1);
- mw->menu.free_top_shadow_color_p = 0;
+ x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+ *free_top_p = False;
}
- mw->menu.top_shadow_color = mw->core.background_pixel;
+ *top_color = back_color;
}
else
{
- if (mw->menu.free_bottom_shadow_color_p)
+ if (*free_bottom_p)
{
- x_free_dpy_colors (dpy, screen, cmap,
- &mw->menu.bottom_shadow_color, 1);
- mw->menu.free_bottom_shadow_color_p = 0;
+ x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+ *free_bottom_p = False;
}
- mw->menu.bottom_shadow_color = mw->menu.foreground;
+ *bottom_color = fore_color;
}
}
}
- if (!mw->menu.top_shadow_pixmap
- && mw->menu.top_shadow_color == mw->core.background_pixel)
+ if (!*top_pixmap && *top_color == back_color)
{
- mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
- if (mw->menu.free_top_shadow_color_p)
+ *top_pixmap = mw->menu.gray_pixmap;
+ if (*free_top_p)
{
- x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
- mw->menu.free_top_shadow_color_p = 0;
+ x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+ *free_top_p = False;
}
- mw->menu.top_shadow_color = mw->menu.foreground;
+ *top_color = fore_color;
}
- if (!mw->menu.bottom_shadow_pixmap
- && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+ if (!*bottom_pixmap && *bottom_color == back_color)
{
- mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
- if (mw->menu.free_bottom_shadow_color_p)
+ *bottom_pixmap = mw->menu.gray_pixmap;
+ if (*free_bottom_p)
{
- x_free_dpy_colors (dpy, screen, cmap,
- &mw->menu.bottom_shadow_color, 1);
- mw->menu.free_bottom_shadow_color_p = 0;
+ x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+ *free_bottom_p = False;
}
- mw->menu.bottom_shadow_color = mw->menu.foreground;
+ *bottom_color = fore_color;
}
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+ XGCValues xgcv;
+ unsigned long pm = 0;
+ Pixel highlight_fg;
+
+ highlight_fg = mw->menu.highlight_foreground;
+
+ if (highlight_fg == -1)
+ highlight_fg = mw->menu.foreground;
+
+ /* Normal shadows */
+ compute_shadow_colors (mw, &(mw->menu.top_shadow_color),
+ &(mw->menu.bottom_shadow_color),
+ &(mw->menu.free_top_shadow_color_p),
+ &(mw->menu.free_bottom_shadow_color_p),
+ &(mw->menu.top_shadow_pixmap),
+ &(mw->menu.bottom_shadow_pixmap),
+ mw->menu.foreground, mw->core.background_pixel);
+
+ /* Highlight shadows */
+ compute_shadow_colors (mw, &(mw->menu.top_highlight_shadow_color),
+ &(mw->menu.bottom_highlight_shadow_color),
+ &(mw->menu.free_top_highlight_shadow_color_p),
+ &(mw->menu.free_bottom_highlight_shadow_color_p),
+ &(mw->menu.top_highlight_shadow_pixmap),
+ &(mw->menu.bottom_highlight_shadow_pixmap),
+ highlight_fg, mw->menu.highlight_background);
xgcv.fill_style = FillStippled;
xgcv.foreground = mw->menu.top_shadow_color;
xgcv.stipple = mw->menu.top_shadow_pixmap;
- pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
- mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+ pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+ mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
xgcv.foreground = mw->menu.bottom_shadow_color;
xgcv.stipple = mw->menu.bottom_shadow_pixmap;
- pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
- mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+ pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+ mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+ xgcv.foreground = mw->menu.top_highlight_shadow_color;
+ xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+ pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+ mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+ xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+ xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+ pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+ mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
}
-
static void
release_shadow_gcs (XlwMenuWidget mw)
{
Display *dpy = XtDisplay ((Widget) mw);
Screen *screen = XtScreen ((Widget) mw);
Colormap cmap = mw->core.colormap;
- Pixel px[2];
+ Pixel px[4];
int i = 0;
if (mw->menu.free_top_shadow_color_p)
px[i++] = mw->menu.top_shadow_color;
if (mw->menu.free_bottom_shadow_color_p)
px[i++] = mw->menu.bottom_shadow_color;
+ if (mw->menu.free_top_highlight_shadow_color_p)
+ px[i++] = mw->menu.top_highlight_shadow_color;
+ if (mw->menu.free_bottom_highlight_shadow_color_p)
+ px[i++] = mw->menu.bottom_highlight_shadow_color;
if (i > 0)
x_free_dpy_colors (dpy, screen, cmap, px, i);
XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_top_gc);
+ XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_bottom_gc);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
static XftFont *
getDefaultXftFont (XlwMenuWidget mw)
{
@@ -1869,6 +2060,46 @@ openXftFont (XlwMenuWidget mw)
return mw->menu.xft_font != 0;
}
+
+static void
+update_xft_colors (Widget w)
+{
+ XlwMenuWidget mw;
+ XColor colors[4];
+
+ mw = (XlwMenuWidget) w;
+
+ 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
+ = mw->menu.disabled_foreground;
+ colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+ = (mw->menu.highlight_foreground != -1
+ ? mw->menu.highlight_foreground
+ : mw->menu.foreground);
+
+ XQueryColors (XtDisplay (mw), mw->core.colormap,
+ colors, 4);
+
+ mw->menu.xft_fg.color.alpha = 0xFFFF;
+ mw->menu.xft_fg.color.red = colors[0].red;
+ mw->menu.xft_fg.color.green = colors[0].green;
+ mw->menu.xft_fg.color.blue = colors[0].blue;
+ mw->menu.xft_bg.color.alpha = 0xFFFF;
+ mw->menu.xft_bg.color.red = colors[1].red;
+ mw->menu.xft_bg.color.green = colors[1].green;
+ mw->menu.xft_bg.color.blue = colors[1].blue;
+ mw->menu.xft_disabled_fg.color.alpha = 0xFFFF;
+ mw->menu.xft_disabled_fg.color.red = colors[2].red;
+ mw->menu.xft_disabled_fg.color.green = colors[2].green;
+ mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+ mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+ mw->menu.xft_highlight_fg.color.red = colors[3].red;
+ mw->menu.xft_highlight_fg.color.green = colors[3].green;
+ mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
+}
#endif
static void
@@ -1887,7 +2118,7 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
gray_width, gray_height,
(unsigned long)1, (unsigned long)0, 1);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (openXftFont (mw))
;
else
@@ -1910,6 +2141,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
#endif
+ mw->menu.top_highlight_shadow_color = -1;
+ mw->menu.bottom_highlight_shadow_color = -1;
+ mw->menu.top_highlight_shadow_pixmap = None;
+ mw->menu.bottom_highlight_shadow_pixmap = None;
+
make_drawing_gcs (mw);
make_shadow_gcs (mw);
@@ -1933,7 +2169,7 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
mw->menu.windows [0].height = 0;
mw->menu.windows [0].max_rest_width = 0;
mw->menu.windows [0].pixmap = None;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
mw->menu.windows [0].xft_draw = 0;
#endif
size_menu (mw, 0);
@@ -1981,28 +2217,9 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
set_window_type (mw->menu.windows [0].w, mw);
create_pixmap_for_menu (&mw->menu.windows [0], mw);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (mw->menu.xft_font)
- {
- XColor colors[3];
- 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
- = mw->menu.disabled_foreground;
- XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
- mw->menu.xft_fg.color.alpha = 0xFFFF;
- mw->menu.xft_fg.color.red = colors[0].red;
- mw->menu.xft_fg.color.green = colors[0].green;
- mw->menu.xft_fg.color.blue = colors[0].blue;
- mw->menu.xft_bg.color.alpha = 0xFFFF;
- mw->menu.xft_bg.color.red = colors[1].red;
- mw->menu.xft_bg.color.green = colors[1].green;
- mw->menu.xft_bg.color.blue = colors[1].blue;
- mw->menu.xft_disabled_fg.color.alpha = 0xFFFF;
- mw->menu.xft_disabled_fg.color.red = colors[2].red;
- mw->menu.xft_disabled_fg.color.green = colors[2].green;
- mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
- }
+ update_xft_colors (w);
#endif
}
@@ -2044,8 +2261,10 @@ XlwMenuDestroy (Widget w)
if (pointer_grabbed)
ungrab_all ((Widget)w, CurrentTime);
pointer_grabbed = 0;
+ keyboard_grabbed = 0;
- submenu_destroyed = 1;
+ if (!XtIsShell (XtParent (w)))
+ submenu_destroyed = 1;
release_drawing_gcs (mw);
release_shadow_gcs (mw);
@@ -2078,7 +2297,7 @@ XlwMenuDestroy (Widget w)
if (mw->menu.font)
XFreeFont (XtDisplay (mw), mw->menu.font);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (mw->menu.windows [0].xft_draw)
XftDrawDestroy (mw->menu.windows [0].xft_draw);
if (mw->menu.xft_font)
@@ -2092,7 +2311,7 @@ XlwMenuDestroy (Widget w)
{
if (mw->menu.windows [i].pixmap != None)
XFreePixmap (XtDisplay (mw), mw->menu.windows [i].pixmap);
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (mw->menu.windows [i].xft_draw)
XftDrawDestroy (mw->menu.windows [i].xft_draw);
#endif
@@ -2102,7 +2321,7 @@ XlwMenuDestroy (Widget w)
XtFree ((char *) mw->menu.windows);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
static int
fontname_changed (XlwMenuWidget newmw,
XlwMenuWidget oldmw)
@@ -2134,7 +2353,7 @@ XlwMenuSetValues (Widget current, Widget request, Widget new,
if (newmw->core.background_pixel != oldmw->core.background_pixel
|| newmw->menu.foreground != oldmw->menu.foreground
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
|| fontname_changed (newmw, oldmw)
#endif
#ifdef HAVE_X_I18N
@@ -2168,9 +2387,15 @@ XlwMenuSetValues (Widget current, Widget request, Widget new,
XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
0, 0, 0, 0, True);
}
+
+ /* Colors changed. Update the Xft colors as well. */
+#if defined USE_CAIRO || defined HAVE_XFT
+ if (oldmw->menu.xft_font)
+ update_xft_colors (new);
+#endif
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (fontname_changed (newmw, oldmw))
{
int i;
@@ -2587,7 +2812,21 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
int borderwidth = mw->menu.shadow_thickness;
Screen* screen = XtScreen (mw);
Display *display = XtDisplay (mw);
+ int screen_x;
+ int screen_y;
+ int screen_w;
+ int screen_h;
+#ifdef emacs
+ xlw_monitor_dimensions_at_pos (display, screen, x, y,
+ &screen_x, &screen_y,
+ &screen_w, &screen_h);
+#else
+ screen_x = 0;
+ screen_y = 0;
+ screen_w = WidthOfScreen (screen);
+ screen_h = HeightOfScreen (screen);
+#endif
next_release_must_exit = 0;
mw->menu.inside_entry = NULL;
@@ -2601,14 +2840,14 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
x -= borderwidth;
y -= borderwidth;
- if (x < borderwidth)
- x = borderwidth;
- if (x + w + 2 * borderwidth > WidthOfScreen (screen))
- x = WidthOfScreen (screen) - w - 2 * borderwidth;
- if (y < borderwidth)
- y = borderwidth;
- if (y + h + 2 * borderwidth> HeightOfScreen (screen))
- y = HeightOfScreen (screen) - h - 2 * borderwidth;
+ if (x < screen_x + borderwidth)
+ x = screen_x + borderwidth;
+ if (x + w + 2 * borderwidth > screen_x + screen_w)
+ x = (screen_x + screen_w) - w - 2 * borderwidth;
+ if (y < screen_y + borderwidth)
+ y = screen_y + borderwidth;
+ if (y + h + 2 * borderwidth > screen_y + screen_h)
+ y = (screen_y + screen_h) - h - 2 * borderwidth;
mw->menu.popped_up = True;
if (XtIsShell (XtParent ((Widget)mw)))
@@ -2646,15 +2885,22 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
mw->menu.cursor_shape,
event->time) == Success)
{
- if (! GRAB_KEYBOARD
- || XtGrabKeyboard ((Widget)mw, False, GrabModeAsync,
- GrabModeAsync, event->time) == Success)
+ if (true
+#ifdef emacs
+ && lucid__menu_grab_keyboard
+#endif
+ && XtGrabKeyboard ((Widget) mw, False, GrabModeAsync,
+ GrabModeAsync, event->time) == Success)
{
- XtSetKeyboardFocus((Widget)mw, None);
+ XtSetKeyboardFocus ((Widget) mw, None);
pointer_grabbed = 1;
+ keyboard_grabbed = 1;
}
else
- XtUngrabPointer ((Widget)mw, event->time);
+ {
+ XtUngrabPointer ((Widget) mw, event->time);
+ keyboard_grabbed = 0;
+ }
}
#ifdef emacs
@@ -2668,4 +2914,6 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
((XMotionEvent*)event)->is_hint = 0;
handle_motion_event (mw, (XMotionEvent*)event);
+
+ XlwMenuRedisplay ((Widget) mw, NULL, None);
}
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7c278396253..4e36bde3fb9 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -1,6 +1,6 @@
/* Interface of a lightweight menubar widget.
-Copyright (C) 2002-2017 Free Software Foundation, Inc.
+Copyright (C) 2002-2022 Free Software Foundation, Inc.
Copyright (C) 1992 Lucid, Inc.
This file is part of the Lucid Widget Library.
@@ -56,6 +56,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#define XtCResizeToPreferred "ResizeToPreferred"
#define XtNallowResize "allowResize"
#define XtCAllowResize "AllowResize"
+#define XtNborderThickness "borderThickness"
+#define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
/* Motif-compatible resource names */
#define XmNshadowThickness "shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index e7be866be79..c314eb3e910 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -1,6 +1,6 @@
/* Internals of a lightweight menubar widget.
-Copyright (C) 2002-2017 Free Software Foundation, Inc.
+Copyright (C) 2002-2022 Free Software Foundation, Inc.
Copyright (C) 1992 Lucid, Inc.
This file is part of the Lucid Widget Library.
@@ -23,9 +23,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "xlwmenu.h"
#include <X11/CoreP.h>
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
+#ifdef USE_CAIRO
+#include "lwlib-utils.h"
+#else /* HAVE_XFT */
#include <X11/Xft/Xft.h>
#endif
+#endif
/* Elements in the stack arrays. */
typedef struct _window_state
@@ -42,7 +46,7 @@ typedef struct _window_state
/* Width of toggle buttons or radio buttons. */
Dimension button_width;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
XftDraw* xft_draw;
#endif
} window_state;
@@ -56,25 +60,32 @@ typedef struct _XlwMenu_part
XFontSet fontSet;
XFontSetExtents *font_extents;
#endif
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
int default_face;
XftFont* xft_font;
- XftColor xft_fg, xft_bg, xft_disabled_fg;
+ XftColor xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
#endif
String fontName;
XFontStruct* font;
Pixel foreground;
Pixel disabled_foreground;
Pixel button_foreground;
+ Pixel highlight_foreground;
+ Pixel highlight_background;
Dimension margin;
Dimension horizontal_spacing;
Dimension vertical_spacing;
Dimension arrow_spacing;
Dimension shadow_thickness;
+ Dimension border_thickness;
Pixel top_shadow_color;
Pixel bottom_shadow_color;
Pixmap top_shadow_pixmap;
Pixmap bottom_shadow_pixmap;
+ Pixel top_highlight_shadow_color;
+ Pixel bottom_highlight_shadow_color;
+ Pixmap top_highlight_shadow_pixmap;
+ Pixmap bottom_highlight_shadow_pixmap;
Cursor cursor_shape;
XtCallbackList open;
XtCallbackList select, highlight;
@@ -83,8 +94,10 @@ typedef struct _XlwMenu_part
int horizontal;
/* True means top_shadow_color and/or bottom_shadow_color must be freed. */
- bool_bf free_top_shadow_color_p : 1;
- bool_bf free_bottom_shadow_color_p : 1;
+ Boolean free_top_shadow_color_p;
+ Boolean free_bottom_shadow_color_p;
+ Boolean free_top_highlight_shadow_color_p;
+ Boolean free_bottom_highlight_shadow_color_p;
/* State of the XlwMenu */
int top_depth;
@@ -107,9 +120,13 @@ typedef struct _XlwMenu_part
GC button_gc;
GC background_gc;
GC disabled_gc;
+ GC highlight_foreground_gc;
+ GC highlight_background_gc;
GC inactive_button_gc;
GC shadow_top_gc;
GC shadow_bottom_gc;
+ GC highlight_shadow_top_gc;
+ GC highlight_shadow_bottom_gc;
Cursor cursor;
Boolean popped_up;
Pixmap gray_pixmap;