@@ -190,8 +190,9 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri
int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
bool direction)
{
- int step, line_step, pbytes, ret;
+ int step, line_step, pbytes, ret, row;
void *line, *dst;
+ u32 *save_ptr;
uint value;
ret = check_bpix_support(vid_priv->bpix);
@@ -207,20 +208,72 @@ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
line_step = vid_priv->line_length;
}
+ /* we should not already have saved data */
+ if (curs->saved) {
+ debug("Trying to show cursor but data is already saved\n");
+ return -EINVAL;
+ }
+
/* Figure out where to write the cursor in the frame buffer */
line = vid_priv->fb + curs->y * vid_priv->line_length +
curs->x * VNBYTES(vid_priv->bpix);
+ /* save pixels under cursor and draw new cursor in one pass */
value = vid_priv->colour_fg;
-
- for (int row = 0; row < curs->height; row++) {
+ save_ptr = curs->save_data;
+ for (row = 0; row < curs->height; row++) {
dst = line;
for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++)
- fill_pixel_and_goto_next(&dst, value, pbytes, step);
-
+ *save_ptr++ = swap_pixel_and_goto_next(&dst, value,
+ pbytes, step);
line += line_step;
}
+ curs->saved = true;
+
+ return 0;
+}
+
+int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
+ bool direction)
+{
+ int step, line_step, pbytes, ret;
+ void *line, *dst;
+
+ ret = check_bpix_support(vid_priv->bpix);
+ if (ret)
+ return ret;
+
+ pbytes = VNBYTES(vid_priv->bpix);
+ if (direction) {
+ step = -pbytes;
+ line_step = -vid_priv->line_length;
+ } else {
+ step = pbytes;
+ line_step = vid_priv->line_length;
+ }
+
+ /* Trying to hide cursor - we should have saved data */
+ if (!curs->saved) {
+ debug("Trying to hide cursor but no data was saved\n");
+ return -EINVAL;
+ }
+
+ /* Figure out where to write the cursor in the frame buffer */
+ line = vid_priv->fb + curs->y * vid_priv->line_length +
+ curs->x * VNBYTES(vid_priv->bpix);
+
+ /* Restore saved pixels */
+ u32 *save_ptr = curs->save_data;
+ dst = line;
+ for (int row = 0; row < curs->height; row++) {
+ void *row_dst = dst;
+ for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++)
+ fill_pixel_and_goto_next(&row_dst, *save_ptr++, pbytes,
+ step);
+ dst += line_step;
+ }
+ curs->saved = false;
return 0;
}
@@ -71,6 +71,9 @@ static int vidconsole_back(struct udevice *dev)
return ret;
}
+ /* Hide cursor at old position if it's visible */
+ vidconsole_hide_cursor(dev);
+
priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
if (priv->xcur_frac < priv->xstart_frac) {
priv->xcur_frac = (priv->cols - 1) *
@@ -128,6 +131,9 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
{
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ /* Hide cursor at old position if it's visible */
+ vidconsole_hide_cursor(dev);
+
priv->xcur_frac = VID_TO_POS(x);
priv->xstart_frac = priv->xcur_frac;
priv->ycur = y;
@@ -473,6 +479,9 @@ int vidconsole_put_char(struct udevice *dev, char ch)
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
int cp, ret;
+ /* Hide cursor to avoid artifacts */
+ vidconsole_hide_cursor(dev);
+
if (priv->escape) {
vidconsole_escape_char(dev, ch);
return 0;
@@ -752,6 +761,33 @@ int vidconsole_show_cursor(struct udevice *dev)
return 0;
}
+int vidconsole_hide_cursor(struct udevice *dev)
+{
+ struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+ struct vidconsole_cursor *curs = &priv->curs;
+ int ret;
+
+ if (!curs->visible)
+ return 0;
+
+ /* If the driver stored cursor line and height, use them for drawing */
+ if (curs->height) {
+ struct udevice *vid = dev_get_parent(dev);
+ struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+
+ ret = cursor_hide(curs, vid_priv, NORMAL_DIRECTION);
+ if (ret)
+ return ret;
+
+ /* Update display damage for cursor area */
+ video_damage(vid, curs->x, curs->y, VIDCONSOLE_CURSOR_WIDTH,
+ curs->height);
+ }
+
+ curs->visible = false;
+
+ return 0;
+}
#endif /* CONFIG_CURSOR */
int vidconsole_mark_start(struct udevice *dev)
@@ -112,7 +112,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri
struct video_fontdata *fontdata, bool direction);
/**
- * cursor_show() - Draw a simple vertical cursor
+ * cursor_show() - Show cursor by saving and drawing pixels
*
* @curs: cursor information
* @vid_priv: video-device info
@@ -130,11 +130,22 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri
*|---!!we're starting from upper left char corner|
*|-----------------------------------------------|
*
- * Return: 0, if success, or else error code.
+ * Return: 0 on success, -EINVAL if cursor data already saved
*/
int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
bool direction);
+/**
+ * cursor_hide() - Hide cursor by restoring saved pixels
+ *
+ * @curs: cursor information
+ * @vid_priv: video-device info
+ * @direction: controls cursor orientation (normal or flipped)
+ * Return: 0 if success, -EINVAL if no cursor data was saved
+ */
+int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
+ bool direction);
+
/**
* console_alloc_cursor() - Allocate cursor save buffer
*
@@ -462,6 +462,16 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf);
*/
int vidconsole_show_cursor(struct udevice *dev);
+/**
+ * vidconsole_hide_cursor() - Hide the cursor
+ *
+ * Hides the cursor if it's currently visible
+ *
+ * @dev: Console device to use
+ * Return: 0 if OK, -ve on error
+ */
+int vidconsole_hide_cursor(struct udevice *dev);
+
/**
* vidconsole_readline_start() - Enable cursor for all video consoles
*
@@ -485,6 +495,11 @@ static inline int vidconsole_show_cursor(struct udevice *dev)
return 0;
}
+static inline int vidconsole_hide_cursor(struct udevice *dev)
+{
+ return 0;
+}
+
static inline void vidconsole_readline_start(bool indent)
{
}
@@ -501,7 +516,6 @@ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by)
}
/**
-
* vidconsole_push_colour() - Temporarily change the font colour
*
* @dev: Device to adjust