Index: uspace/lib/ui/include/ui/menu.h
===================================================================
--- uspace/lib/ui/include/ui/menu.h	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/include/ui/menu.h	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -52,5 +52,6 @@
 extern errno_t ui_menu_paint(ui_menu_t *, gfx_coord2_t *);
 extern errno_t ui_menu_unpaint(ui_menu_t *);
-extern void ui_menu_press(ui_menu_t *, gfx_coord2_t *, gfx_coord2_t *);
+extern ui_evclaim_t ui_menu_pos_event(ui_menu_t *, gfx_coord2_t *,
+    pos_event_t *);
 
 #endif
Index: uspace/lib/ui/include/ui/menuentry.h
===================================================================
--- uspace/lib/ui/include/ui/menuentry.h	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/include/ui/menuentry.h	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -53,6 +53,10 @@
 extern gfx_coord_t ui_menu_entry_height(ui_menu_entry_t *);
 extern errno_t ui_menu_entry_paint(ui_menu_entry_t *, gfx_coord2_t *);
-extern void ui_menu_entry_press(ui_menu_entry_t *, gfx_coord2_t *,
-    gfx_coord2_t *);
+extern void ui_menu_entry_press(ui_menu_entry_t *, gfx_coord2_t *);
+extern void ui_menu_entry_release(ui_menu_entry_t *);
+extern void ui_menu_entry_enter(ui_menu_entry_t *, gfx_coord2_t *);
+extern void ui_menu_entry_leave(ui_menu_entry_t *, gfx_coord2_t *);
+extern ui_evclaim_t ui_menu_entry_pos_event(ui_menu_entry_t *, gfx_coord2_t *,
+    pos_event_t *);
 
 #endif
Index: uspace/lib/ui/private/menuentry.h
===================================================================
--- uspace/lib/ui/private/menuentry.h	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/private/menuentry.h	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -53,4 +53,8 @@
 	/** Callbacks */
 	ui_menu_entry_cb_t cb;
+	/** Menu entry is currently held down */
+	bool held;
+	/** Pointer is currently inside */
+	bool inside;
 	/** Callback argument */
 	void *arg;
Index: uspace/lib/ui/src/menu.c
===================================================================
--- uspace/lib/ui/src/menu.c	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/src/menu.c	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -292,13 +292,19 @@
  * @param menu Menu
  * @param spos Starting position (top-left corner)
- * @param ppos Press position
- */
-void ui_menu_press(ui_menu_t *menu, gfx_coord2_t *spos, gfx_coord2_t *ppos)
+ * @param event Position event
+ * @return ui_claimed iff the event was claimed
+ */
+ui_evclaim_t ui_menu_pos_event(ui_menu_t *menu, gfx_coord2_t *spos,
+    pos_event_t *event)
 {
 	ui_menu_geom_t geom;
 	ui_menu_entry_t *mentry;
 	gfx_coord2_t pos;
+	gfx_coord2_t epos;
+	ui_evclaim_t claimed;
 
 	ui_menu_get_geom(menu, spos, &geom);
+	epos.x = event->hpos;
+	epos.y = event->vpos;
 
 	pos = geom.entries_rect.p0;
@@ -306,9 +312,16 @@
 	mentry = ui_menu_entry_first(menu);
 	while (mentry != NULL) {
-		ui_menu_entry_press(mentry, &pos, ppos);
+		claimed = ui_menu_entry_pos_event(mentry, &pos, event);
+		if (claimed == ui_claimed)
+			return ui_claimed;
 
 		pos.y += ui_menu_entry_height(mentry);
 		mentry = ui_menu_entry_next(mentry);
 	}
+
+	if (gfx_pix_inside_rect(&epos, &geom.outer_rect))
+		return ui_claimed;
+
+	return ui_unclaimed;
 }
 
Index: uspace/lib/ui/src/menubar.c
===================================================================
--- uspace/lib/ui/src/menubar.c	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/src/menubar.c	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -267,8 +267,8 @@
  *
  * @param mbar Menu bar
- * @param ppos Press position
+ * @param pos_event Position event
  * @return @c ui_claimed iff the event is claimed
  */
-static ui_evclaim_t ui_menu_bar_press(ui_menu_bar_t *mbar, gfx_coord2_t *ppos)
+ui_evclaim_t ui_menu_bar_pos_event(ui_menu_bar_t *mbar, pos_event_t *event)
 {
 	gfx_coord2_t pos;
@@ -279,4 +279,9 @@
 	gfx_coord_t width;
 	gfx_coord_t hpad;
+	gfx_coord2_t ppos;
+	ui_evclaim_t claimed;
+
+	ppos.x = event->hpos;
+	ppos.y = event->vpos;
 
 	if (mbar->res->textmode) {
@@ -298,5 +303,6 @@
 
 		/* Check if press is inside menu bar entry */
-		if (gfx_pix_inside_rect(ppos, &rect)) {
+		if (event->type == POS_PRESS &&
+		    gfx_pix_inside_rect(&ppos, &rect)) {
 			ui_menu_bar_select(mbar, &pos, menu);
 			return ui_claimed;
@@ -310,36 +316,11 @@
 			ui_menu_get_rect(menu, &spos, &rect);
 
-			/* Check if press is inside open menu */
-			if (gfx_pix_inside_rect(ppos, &rect)) {
-				ui_menu_press(menu, &spos, ppos);
+			claimed = ui_menu_pos_event(menu, &spos, event);
+			if (claimed == ui_claimed)
 				return ui_claimed;
-			}
 		}
 
 		pos.x += width;
 		menu = ui_menu_next(menu);
-	}
-
-	return ui_unclaimed;
-}
-
-/** Handle menu bar position event.
- *
- * @param mbar Menu bar
- * @param pos_event Position event
- * @return @c ui_claimed iff the event is claimed
- */
-ui_evclaim_t ui_menu_bar_pos_event(ui_menu_bar_t *mbar, pos_event_t *event)
-{
-	gfx_coord2_t pos;
-
-	pos.x = event->hpos;
-	pos.y = event->vpos;
-
-	switch (event->type) {
-	case POS_PRESS:
-		return ui_menu_bar_press(mbar, &pos);
-	default:
-		break;
 	}
 
Index: uspace/lib/ui/src/menuentry.c
===================================================================
--- uspace/lib/ui/src/menuentry.c	(revision bfb055b5d8b4b517c36ae0332c76d2f90f85bd12)
+++ uspace/lib/ui/src/menuentry.c	(revision cd6287931f05186767f2ccee516423a0342dfad2)
@@ -217,5 +217,6 @@
 	caption = mentry->caption;
 
-	if (mentry == mentry->menu->selected) {
+	if ((mentry->held && mentry->inside) ||
+	    mentry == mentry->menu->selected) {
 		fmt.color = res->wnd_sel_text_color;
 		bg_color = res->wnd_sel_text_bg_color;
@@ -249,17 +250,28 @@
  *
  * @param mentry Menu entry
- * @param pos Position (top-left corner)
- * @param ppos Press position
- */
-void ui_menu_entry_press(ui_menu_entry_t *mentry, gfx_coord2_t *pos,
-    gfx_coord2_t *ppos)
-{
-	ui_menu_entry_geom_t geom;
-
-	ui_menu_entry_get_geom(mentry, pos, &geom);
-
-	if (gfx_pix_inside_rect(ppos, &geom.outer_rect)) {
-		/* Press inside menu entry */
-
+ * @param pos Menu entry position
+ */
+void ui_menu_entry_press(ui_menu_entry_t *mentry, gfx_coord2_t *pos)
+{
+	if (mentry->held)
+		return;
+
+	mentry->inside = true;
+	mentry->held = true;
+	ui_menu_entry_paint(mentry, pos);
+}
+
+/** Handle button release in menu entry.
+ *
+ * @param mentry Menu entry
+ */
+void ui_menu_entry_release(ui_menu_entry_t *mentry)
+{
+	if (!mentry->held)
+		return;
+
+	mentry->held = false;
+
+	if (mentry->inside) {
 		/* Close menu */
 		ui_menu_bar_select(mentry->menu->mbar,
@@ -270,4 +282,80 @@
 			mentry->cb(mentry, mentry->arg);
 	}
+}
+
+/** Pointer entered menu entry.
+ *
+ * @param mentry Menu entry
+ * @param pos Menu entry position
+ */
+void ui_menu_entry_enter(ui_menu_entry_t *mentry, gfx_coord2_t *pos)
+{
+	if (mentry->inside)
+		return;
+
+	mentry->inside = true;
+	if (mentry->held)
+		(void) ui_menu_entry_paint(mentry, pos);
+}
+
+/** Pointer left menu entry.
+ *
+ * @param mentry Menu entry
+ * @param pos Menu entry position
+ */
+void ui_menu_entry_leave(ui_menu_entry_t *mentry, gfx_coord2_t *pos)
+{
+	if (!mentry->inside)
+		return;
+
+	mentry->inside = false;
+	if (mentry->held)
+		(void) ui_menu_entry_paint(mentry, pos);
+}
+
+/** Handle menu entry position event.
+ *
+ * @param mentry Menu entry
+ * @param pos Menu entry position (top-left corner)
+ * @param pos_event Position event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t ui_menu_entry_pos_event(ui_menu_entry_t *mentry,
+    gfx_coord2_t *pos, pos_event_t *event)
+{
+	ui_menu_entry_geom_t geom;
+	gfx_coord2_t ppos;
+	bool inside;
+
+	ppos.x = event->hpos;
+	ppos.y = event->vpos;
+
+	ui_menu_entry_get_geom(mentry, pos, &geom);
+	inside = gfx_pix_inside_rect(&ppos, &geom.outer_rect);
+
+	switch (event->type) {
+	case POS_PRESS:
+		if (inside) {
+			ui_menu_entry_press(mentry, pos);
+			return ui_claimed;
+		}
+		break;
+	case POS_RELEASE:
+		if (mentry->held) {
+			ui_menu_entry_release(mentry);
+			return ui_claimed;
+		}
+		break;
+	case POS_UPDATE:
+		if (inside && !mentry->inside) {
+			ui_menu_entry_enter(mentry, pos);
+			return ui_claimed;
+		} else if (!inside && mentry->inside) {
+			ui_menu_entry_leave(mentry, pos);
+		}
+		break;
+	}
+
+	return ui_unclaimed;
 }
 
