summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTonCherAmi <kratos661@gmail.com>2021-05-23 01:17:27 +0300
committerGitHub <noreply@github.com>2021-05-23 00:17:27 +0200
commitdc28a974373b5d462a734e35b8b47afce0782c77 (patch)
tree432760a640e58924da590016b4c99881a32d993d
parent04c006a4a23dd71a3c4af8df63329ab436411740 (diff)
Add cursor property (#1313)
* Change mouse cursor on widget hover Currently only listview element and editbox are supported. * Add cursor property
-rw-r--r--.travis.yml1
-rw-r--r--INSTALL.md1
-rw-r--r--configure.ac2
-rw-r--r--doc/default_theme.rasi5
-rw-r--r--doc/rofi-theme.515
-rw-r--r--doc/rofi-theme.5.markdown9
-rw-r--r--include/rofi-types.h12
-rw-r--r--include/theme.h11
-rw-r--r--include/widgets/widget-internal.h3
-rw-r--r--include/xcb.h23
-rw-r--r--lexer/theme-lexer.l10
-rw-r--r--lexer/theme-parser.y15
-rw-r--r--meson.build1
-rw-r--r--source/rofi-types.c2
-rw-r--r--source/theme.c26
-rw-r--r--source/view.c71
-rw-r--r--source/widgets/widget.c8
-rw-r--r--source/xcb.c49
-rw-r--r--test/theme-parser-test.c29
19 files changed, 284 insertions, 9 deletions
diff --git a/.travis.yml b/.travis.yml
index 9ddc0b6f..2dee9340 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,6 +35,7 @@ addons:
- libxcb-xinerama0-dev
- libxcb-xkb-dev
- libxcb-xrm-dev
+ - libxcb-cursor-dev
- libxkbcommon-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
diff --git a/INSTALL.md b/INSTALL.md
index eb60573a..2df73997 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -40,6 +40,7 @@ You can also use [Meson](https://mesonbuild.com/) as an alternative.
* xcb-util-wm (sometimes split as libxcb-ewmh and libxcb-icccm)
* xcb-util-xrm [new module might not be available in your distribution. The source can be found
here](https://github.com/Airblader/xcb-util-xrm/)
+* xcb-util-cursor
On debian based systems, the developer packages are in the form of: `<package>-dev` on rpm based
`<package>-devel`.
diff --git a/configure.ac b/configure.ac
index 03dc1d2f..e561c900 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,7 +144,7 @@ NK_INIT([bindings xdg-theme])
PKG_CHECK_MODULES([glib], [glib-2.0 >= ${glib_min_version} gio-unix-2.0 gmodule-2.0])
AC_DEFINE_UNQUOTED([GLIB_VERSION_MIN_REQUIRED], [(G_ENCODE_VERSION(${glib_min_major},${glib_min_minor}))], [The lower GLib version supported])
AC_DEFINE_UNQUOTED([GLIB_VERSION_MAX_ALLOWED], [(G_ENCODE_VERSION(${glib_min_major},${glib_min_minor}))], [The highest GLib version supported])
-GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-randr xcb-xinerama])
+GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-cursor xcb-randr xcb-xinerama])
PKG_CHECK_MODULES([pango], [pango pangocairo])
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0 ])
diff --git a/doc/default_theme.rasi b/doc/default_theme.rasi
index 4c2b39a5..5c6e3bb5 100644
--- a/doc/default_theme.rasi
+++ b/doc/default_theme.rasi
@@ -35,6 +35,7 @@ element {
padding: 1px ;
spacing: 5px ;
border: 0;
+ cursor: pointer;
}
element normal.normal {
background-color: var(normal-background);
@@ -76,11 +77,13 @@ element-text {
background-color: rgba ( 0, 0, 0, 0 % );
text-color: inherit;
highlight: inherit;
+ cursor: inherit;
}
element-icon {
background-color: rgba ( 0, 0, 0, 0 % );
size: 1.0000em ;
text-color: inherit;
+ cursor: inherit;
}
window {
padding: 5;
@@ -121,6 +124,7 @@ sidebar {
button {
spacing: 0;
text-color: var(normal-foreground);
+ cursor: pointer;
}
button selected {
background-color: var(selected-normal-background);
@@ -151,6 +155,7 @@ entry {
text-color: var(normal-foreground);
placeholder-color: grey;
placeholder: "Type to filter";
+ cursor: text;
}
prompt {
spacing: 0;
diff --git a/doc/rofi-theme.5 b/doc/rofi-theme.5
index 3a555fdb..ad4d61dd 100644
--- a/doc/rofi-theme.5
+++ b/doc/rofi-theme.5
@@ -275,6 +275,8 @@ a reference
.IP \(bu 2
an orientation
.IP \(bu 2
+a cursor
+.IP \(bu 2
a list of keywords
.IP \(bu 2
an environment variable
@@ -754,6 +756,16 @@ Format: \fB\fC(horizontal|vertical)\fR
.PP
Specify the orientation of the widget.
+.SH Cursor
+.RS
+.IP \(bu 2
+Format: \fB\fC(default|pointer|text)\fR
+
+.RE
+
+.PP
+Specify the type of mouse cursor that is set when the mouse pointer is over the widget.
+
.SH List of keywords
.RS
.IP \(bu 2
@@ -1012,6 +1024,9 @@ Background color
.IP \(bu 2
\fBborder\-color\fP: color
Color of the border
+.IP \(bu 2
+\fBcursor\fP: cursor
+Type of mouse cursor that is set when the mouse pointer is hovered over the widget.
.RE
diff --git a/doc/rofi-theme.5.markdown b/doc/rofi-theme.5.markdown
index 4dd20b24..0f9dc6dc 100644
--- a/doc/rofi-theme.5.markdown
+++ b/doc/rofi-theme.5.markdown
@@ -189,6 +189,7 @@ The current theme format supports different types:
* a position
* a reference
* an orientation
+ * a cursor
* a list of keywords
* an environment variable
* Inherit
@@ -462,6 +463,12 @@ window {
Specify the orientation of the widget.
+## Cursor
+
+ * Format: `(default|pointer|text)`
+
+Specify the type of mouse cursor that is set when the mouse pointer is over the widget.
+
## List of keywords
* Format: `[ keyword, keyword ]`
@@ -620,6 +627,8 @@ The following properties are currently supported:
Background color
* **border-color**: color
Color of the border
+* **cursor**: cursor
+ Type of mouse cursor that is set when the mouse pointer is hovered over the widget.
### window:
diff --git a/include/rofi-types.h b/include/rofi-types.h
index bdda445f..9bf8869f 100644
--- a/include/rofi-types.h
+++ b/include/rofi-types.h
@@ -33,6 +33,8 @@ typedef enum
P_LIST,
/** Orientation */
P_ORIENTATION,
+ /** Cursor */
+ P_CURSOR,
/** Inherit */
P_INHERIT,
/** Number of types. */
@@ -141,6 +143,16 @@ typedef enum
} RofiOrientation;
/**
+ * Cursor type.
+ */
+typedef enum
+{
+ ROFI_CURSOR_DEFAULT,
+ ROFI_CURSOR_POINTER,
+ ROFI_CURSOR_TEXT
+} RofiCursorType;
+
+/**
* Represent the color in theme.
*/
typedef struct
diff --git a/include/theme.h b/include/theme.h
index 151446bc..ced26183 100644
--- a/include/theme.h
+++ b/include/theme.h
@@ -217,6 +217,17 @@ int rofi_theme_get_boolean ( const widget *widget, const char *property, int
* @returns The orientation of this property for this widget or %def not found.
*/
RofiOrientation rofi_theme_get_orientation ( const widget *widget, const char *property, RofiOrientation def );
+
+/**
+ * @param widget The widget to query
+ * @param property The property to query.
+ * @param def The default value.
+ *
+ * Obtain the cursor indicated by %property of the widget.
+ *
+ * @returns The cursor for this widget or %def if not found.
+ */
+RofiCursorType rofi_theme_get_cursor_type ( const widget *widget, const char *property, RofiCursorType def );
/**
* @param widget The widget to query
* @param property The property to query.
diff --git a/include/widgets/widget-internal.h b/include/widgets/widget-internal.h
index ed028f3c..3106d063 100644
--- a/include/widgets/widget-internal.h
+++ b/include/widgets/widget-internal.h
@@ -54,6 +54,9 @@ struct _widget
RofiPadding border;
RofiPadding border_radius;
+ /** Cursor that is set when the widget is hovered */
+ RofiCursorType cursor_type;
+
/** enabled or not */
gboolean enabled;
/** Expand the widget when packed */
diff --git a/include/xcb.h b/include/xcb.h
index b342e94e..9a71dc38 100644
--- a/include/xcb.h
+++ b/include/xcb.h
@@ -176,6 +176,28 @@ cairo_surface_t *x11_helper_get_screenshot_surface ( void );
void x11_disable_decoration ( xcb_window_t window );
/**
+ * List of cursor types.
+ */
+typedef enum
+{
+ /** Default arrow cursor */
+ CURSOR_DEFAULT = 0,
+ /** Cursor denoting a clickable area */
+ CURSOR_POINTER,
+ /** Cursor denoting an input field / selectable text */
+ CURSOR_TEXT,
+ NUM_CURSORS
+} X11CursorType;
+
+/**
+ * @param window
+ * @param type
+ *
+ * Change mouse cursor
+ */
+void x11_set_cursor ( xcb_window_t window, X11CursorType type );
+
+/**
* List of window managers that need different behaviour to functioning.
*/
typedef enum
@@ -212,4 +234,5 @@ cairo_surface_t *x11_helper_get_screenshot_surface_window ( xcb_window_t window,
* Blur the content of the surface with radius and deviation.
*/
void cairo_image_surface_blur(cairo_surface_t* surface, double radius, double deviation);
+
#endif
diff --git a/lexer/theme-lexer.l b/lexer/theme-lexer.l
index c3bc99d0..48d043a8 100644
--- a/lexer/theme-lexer.l
+++ b/lexer/theme-lexer.l
@@ -227,6 +227,12 @@ LS_SOLID (?i:solid)
ORIENTATION_HORI (?i:horizontal)
ORIENTATION_VERT (?i:vertical)
+/* Cursor */
+
+CURSOR_DEF (?i:default)
+CURSOR_PTR (?i:pointer)
+CURSOR_TXT (?i:text)
+
/* Color schema */
RGBA (?i:rgb[a]?)
HWB (?i:hwb)
@@ -598,6 +604,10 @@ if ( queue == NULL ){
<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ORIENTATION_HORI} { return ORIENTATION_HORI; }
<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{ORIENTATION_VERT} { return ORIENTATION_VERT; }
+<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_DEF} { return CURSOR_DEF; }
+<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_PTR} { return CURSOR_PTR; }
+<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{CURSOR_TXT} { return CURSOR_TXT; }
+
<PROPERTIES,PROPERTIES_ENV,PROPERTIES_VAR_DEFAULT>{COLOR_TRANSPARENT} {
return T_COLOR_TRANSPARENT;
}
diff --git a/lexer/theme-parser.y b/lexer/theme-parser.y
index bb1496db..8efcdc58 100644
--- a/lexer/theme-parser.y
+++ b/lexer/theme-parser.y
@@ -200,6 +200,10 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%token ORIENTATION_HORI "Horizontal"
%token ORIENTATION_VERT "Vertical"
+%token CURSOR_DEF "Default"
+%token CURSOR_PTR "Pointer"
+%token CURSOR_TXT "Text"
+
%token T_COL_RGBA "rgb[a] colorscheme"
%token T_COL_HSL "hsl colorscheme"
%token T_COL_HWB "hwb colorscheme"
@@ -276,6 +280,7 @@ static ThemeColor hwb_to_rgb ( double h, double w, double b)
%type <list> t_property_element_list
%type <list> t_property_element_list_optional
%type <ival> t_property_orientation
+%type <ival> t_property_cursor
%type <ival> t_name_prefix_optional
%start t_main
@@ -512,6 +517,10 @@ t_property_element
$$ = rofi_theme_property_create ( P_ORIENTATION );
$$->value.i = $1;
}
+| t_property_cursor {
+ $$ = rofi_theme_property_create ( P_CURSOR );
+ $$->value.i = $1;
+}
;
/** List of elements */
@@ -846,6 +855,12 @@ t_property_orientation
| ORIENTATION_VERT { $$ = ROFI_ORIENTATION_VERTICAL; }
;
+t_property_cursor
+: CURSOR_DEF { $$ = ROFI_CURSOR_DEFAULT; }
+| CURSOR_PTR { $$ = ROFI_CURSOR_POINTER; }
+| CURSOR_TXT { $$ = ROFI_CURSOR_TEXT; }
+;
+
/** Property name */
t_property_name
: T_PROP_NAME { $$ = $1; }
diff --git a/meson.build b/meson.build
index 67f35a60..98c9de7b 100644
--- a/meson.build
+++ b/meson.build
@@ -66,6 +66,7 @@ deps += [
dependency('xcb-icccm'),
dependency('xcb-xrm'),
dependency('xcb-randr'),
+ dependency('xcb-cursor'),
dependency('xcb-xinerama'),
dependency('cairo-xcb'),
dependency('libstartup-notification-1.0'),
diff --git a/source/rofi-types.c b/source/rofi-types.c
index 690a18c4..2ff4e3e8 100644
--- a/source/rofi-types.c
+++ b/source/rofi-types.c
@@ -28,6 +28,8 @@ const char * const PropertyTypeName[P_NUM_TYPES] = {
"List",
/** Orientation */
"Orientation",
+ /** Cursor */
+ "Cursor",
/** Inherit */
"Inherit",
};
diff --git a/source/theme.c b/source/theme.c
index 26a4b854..2aaa3762 100644
--- a/source/theme.c
+++ b/source/theme.c
@@ -359,6 +359,13 @@ const char * const WindowLocationStr[9] = {
"west"
};
+/** Textual representation of RofiCursorType */
+const char *const RofiCursorTypeStr[3] = {
+ "default",
+ "pointer",
+ "text",
+};
+
static void int_rofi_theme_print_property ( Property *p )
{
switch ( p->type )
@@ -376,6 +383,9 @@ static void int_rofi_theme_print_property ( Property *p )
case P_ORIENTATION:
printf ( "%s", ( p->value.i == ROFI_ORIENTATION_HORIZONTAL ) ? "horizontal" : "vertical" );
break;
+ case P_CURSOR:
+ printf ( "%s", RofiCursorTypeStr[p->value.i] );
+ break;
case P_HIGHLIGHT:
if ( p->value.highlight.style & ROFI_HL_BOLD ) {
printf ( "bold " );
@@ -814,6 +824,22 @@ RofiOrientation rofi_theme_get_orientation ( const widget *widget, const char *p
g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
return def;
}
+RofiCursorType rofi_theme_get_cursor_type ( const widget *widget, const char *property, RofiCursorType def )
+{
+ ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
+ Property *p = rofi_theme_find_property ( wid, P_CURSOR, property, FALSE );
+ if ( p ) {
+ if ( p->type == P_INHERIT ) {
+ if ( widget->parent ) {
+ return rofi_theme_get_cursor_type ( widget->parent, property, def );
+ }
+ return def;
+ }
+ return p->value.i;
+ }
+ g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property );
+ return def;
+}
const char *rofi_theme_get_string ( const widget *widget, const char *property, const char *def )
{
diff --git a/source/view.c b/source/view.c
index 1b2edd76..43b56ab8 100644
--- a/source/view.c
+++ b/source/view.c
@@ -118,6 +118,8 @@ struct
guint repaint_source;
/** Window fullscreen */
gboolean fullscreen;
+ /** Cursor type */
+ X11CursorType cursor_type;
} CacheState = {
.main_window = XCB_WINDOW_NONE,
.fake_bg = NULL,
@@ -722,7 +724,7 @@ static void rofi_view_setup_fake_transparency ( widget *win, const char* const f
}
else {
CacheState.fake_bg = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, CacheState.mon.w, CacheState.mon.h );
-
+
int blur = rofi_theme_get_integer ( WIDGET ( win ), "blur", 0 );
cairo_t *dr = cairo_create ( CacheState.fake_bg );
if ( CacheState.fake_bgrel ) {
@@ -748,10 +750,8 @@ void __create_window ( MenuFlags menu_flags )
uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
uint32_t xcb_event_masks = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION;
- if ( config.hover_select == TRUE ) {
- xcb_event_masks |= XCB_EVENT_MASK_POINTER_MOTION;
- }
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
+
uint32_t selval[] = {
XCB_BACK_PIXMAP_NONE, 0,
XCB_GRAVITY_STATIC,
@@ -1500,19 +1500,65 @@ void rofi_view_handle_text ( RofiViewState *state, char *text )
}
}
+static X11CursorType rofi_cursor_type_to_x11_cursor_type ( RofiCursorType type )
+{
+ switch ( type )
+ {
+ case ROFI_CURSOR_DEFAULT:
+ return CURSOR_DEFAULT;
+
+ case ROFI_CURSOR_POINTER:
+ return CURSOR_POINTER;
+
+ case ROFI_CURSOR_TEXT:
+ return CURSOR_TEXT;
+ }
+
+ return CURSOR_DEFAULT;
+}
+
+static RofiCursorType rofi_view_resolve_cursor ( RofiViewState *state, gint x, gint y ) {
+ widget *target = widget_find_mouse_target ( WIDGET ( state->main_window ), WIDGET_TYPE_UNKNOWN, x, y );
+
+ return target != NULL
+ ? target->cursor_type
+ : ROFI_CURSOR_DEFAULT;
+}
+
+static void rofi_view_set_cursor ( RofiCursorType type )
+{
+ X11CursorType x11_type = rofi_cursor_type_to_x11_cursor_type ( type );
+
+ if ( x11_type == CacheState.cursor_type ) {
+ return;
+ }
+
+ CacheState.cursor_type = x11_type;
+
+ x11_set_cursor ( CacheState.main_window, x11_type );
+}
+
void rofi_view_handle_mouse_motion ( RofiViewState *state, gint x, gint y, gboolean find_mouse_target )
{
state->mouse.x = x;
state->mouse.y = y;
+
+ RofiCursorType cursor_type = rofi_view_resolve_cursor ( state, x, y );
+
+ rofi_view_set_cursor ( cursor_type );
+
if ( find_mouse_target ) {
widget *target = widget_find_mouse_target ( WIDGET ( state->main_window ), SCOPE_MOUSE_LISTVIEW_ELEMENT, x, y );
+
if ( target != NULL ) {
state->mouse.motion_target = target;
}
}
+
if ( state->mouse.motion_target != NULL ) {
widget_xy_to_relative ( state->mouse.motion_target, &x, &y );
widget_motion_notify ( state->mouse.motion_target, x, y );
+
if ( find_mouse_target ) {
state->mouse.motion_target = NULL;
}
@@ -1851,6 +1897,20 @@ static void rofi_view_add_widget ( RofiViewState *state, widget *parent_widget,
}
}
+static void rofi_view_ping_mouse ( RofiViewState *state )
+{
+ xcb_query_pointer_cookie_t pointer_cookie = xcb_query_pointer ( xcb->connection, CacheState.main_window );
+ xcb_query_pointer_reply_t *pointer_reply = xcb_query_pointer_reply ( xcb->connection, pointer_cookie, NULL );
+
+ if ( pointer_reply == NULL ) {
+ return;
+ }
+
+ rofi_view_handle_mouse_motion ( state, pointer_reply->win_x, pointer_reply->win_y, config.hover_select );
+
+ free ( pointer_reply );
+}
+
RofiViewState *rofi_view_create ( Mode *sw,
const char *input,
MenuFlags menu_flags,
@@ -1921,6 +1981,7 @@ RofiViewState *rofi_view_create ( Mode *sw,
rofi_view_update ( state, TRUE );
xcb_map_window ( xcb->connection, CacheState.main_window );
widget_queue_redraw ( WIDGET ( state->main_window ) );
+ rofi_view_ping_mouse ( state );
xcb_flush ( xcb->connection );
/* When Override Redirect, the WM will not let us know we can take focus, so just steal it */
diff --git a/source/widgets/widget.c b/source/widgets/widget.c
index 99bb8736..95ddd52a 100644
--- a/source/widgets/widget.c
+++ b/source/widgets/widget.c
@@ -87,7 +87,9 @@ void widget_init ( widget *wid, widget *parent, WidgetType type, const char *nam
wid->border_radius = rofi_theme_get_padding ( wid, "border-radius", wid->def_border_radius );
wid->margin = rofi_theme_get_padding ( wid, "margin", wid->def_margin );
- // bled by default
+ wid->cursor_type = rofi_theme_get_cursor_type ( wid, "cursor", ROFI_CURSOR_DEFAULT );
+
+ // enabled by default
wid->enabled = rofi_theme_get_boolean ( wid, "enabled", TRUE );
}
@@ -443,9 +445,11 @@ widget *widget_find_mouse_target ( widget *wid, WidgetType type, gint x, gint y
return target;
}
}
- if ( wid->type == type ) {
+
+ if ( wid->type == type || type == WIDGET_TYPE_UNKNOWN ) {
return wid;
}
+
return NULL;
}
diff --git a/source/xcb.c b/source/xcb.c
index c3b9e3ad..ce5722d0 100644
--- a/source/xcb.c
+++ b/source/xcb.c
@@ -45,6 +45,7 @@
#include <xcb/xinerama.h>
#include <xcb/xcb_ewmh.h>
#include <xcb/xproto.h>
+#include <xcb/xcb_cursor.h>
#include <xcb/xkb.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-x11.h>
@@ -70,6 +71,7 @@
/** Checks if the if x and y is inside rectangle. */
#define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) )
+
WindowManagerQuirk current_window_manager = WM_EWHM;
/**
@@ -98,6 +100,18 @@ static xcb_visualtype_t *root_visual = NULL;
xcb_atom_t netatoms[NUM_NETATOMS];
const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) };
+xcb_cursor_t cursors[NUM_CURSORS] = { XCB_CURSOR_NONE, XCB_CURSOR_NONE, XCB_CURSOR_NONE };
+
+const struct
+{
+ const char *css_name;
+ const char *traditional_name;
+} cursor_names[] = {
+ { "default", "left_ptr" },
+ { "pointer", "hand" },
+ { "text", "xterm" }
+};
+
static xcb_visualtype_t * lookup_visual ( xcb_screen_t *s, xcb_visualid_t visual )
{
xcb_depth_iterator_t d;
@@ -1057,7 +1071,7 @@ static void main_loop_x11_event_handler_view ( xcb_generic_event_t *event )
if ( button_mask && config.click_to_exit == TRUE ) {
xcb->mouse_seen = TRUE;
}
- rofi_view_handle_mouse_motion ( state, xme->event_x, xme->event_y, !button_mask );
+ rofi_view_handle_mouse_motion ( state, xme->event_x, xme->event_y, !button_mask && config.hover_select );
break;
}
case XCB_BUTTON_PRESS:
@@ -1504,6 +1518,24 @@ static void x11_create_visual_and_colormap ( void )
}
}
+static void x11_lookup_cursors ( void ) {
+ xcb_cursor_context_t *ctx;
+
+ if ( xcb_cursor_context_new( xcb->connection, xcb->screen, &ctx ) < 0 ) {
+ return;
+ }
+
+ for ( int i = 0; i < NUM_CURSORS; ++i ) {
+ cursors[i] = xcb_cursor_load_cursor ( ctx, cursor_names[i].css_name );
+
+ if ( cursors[i] == XCB_CURSOR_NONE ) {
+ cursors[i] = xcb_cursor_load_cursor ( ctx, cursor_names[i].traditional_name );
+ }
+ }
+
+ xcb_cursor_context_free ( ctx );
+}
+
/** Retry count of grabbing keyboard. */
unsigned int lazy_grab_retry_count_kb = 0;
/** Retry count of grabbing pointer. */
@@ -1540,6 +1572,8 @@ gboolean display_late_setup ( void )
{
x11_create_visual_and_colormap ();
+ x11_lookup_cursors ();
+
/**
* Create window (without showing)
*/
@@ -1633,3 +1667,16 @@ void x11_disable_decoration ( xcb_window_t window )
xcb_atom_t ha = netatoms[_MOTIF_WM_HINTS];
xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, window, ha, ha, 32, 5, &hints );
}
+
+void x11_set_cursor ( xcb_window_t window, X11CursorType type )
+{
+ if ( type < 0 || type >= NUM_CURSORS ) {
+ return;
+ }
+
+ if ( cursors[type] == XCB_CURSOR_NONE ) {
+ return;
+ }
+
+ xcb_change_window_attributes ( xcb->connection, window, XCB_CW_CURSOR, &( cursors[type] ) );
+}
diff --git a/test/theme-parser-test.c b/test/theme-parser-test.c
index dd722468..ab0800bd 100644
--- a/test/theme-parser-test.c
+++ b/test/theme-parser-test.c
@@ -1106,6 +1106,28 @@ START_TEST ( test_properties_orientation_case )
}
END_TEST
+START_TEST ( test_properties_cursor )
+{
+ widget wid;
+ wid.name = "blaat";
+ wid.state = NULL;
+ rofi_theme_parse_string ( "* { def: default; ptr: pointer; txt: text; }");
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "def", ROFI_CURSOR_TEXT), ROFI_CURSOR_DEFAULT);
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "ptr", ROFI_CURSOR_DEFAULT), ROFI_CURSOR_POINTER);
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "txt", ROFI_CURSOR_DEFAULT), ROFI_CURSOR_TEXT);
+}
+END_TEST
+START_TEST ( test_properties_cursor_case )
+{
+ widget wid;
+ wid.name = "blaat";
+ wid.state = NULL;
+ rofi_theme_parse_string ( "* { def: dEfault; ptr: POINter; txt: tExt; }");
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "def", ROFI_CURSOR_TEXT), ROFI_CURSOR_DEFAULT);
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "ptr", ROFI_CURSOR_DEFAULT), ROFI_CURSOR_POINTER);
+ ck_assert_int_eq ( rofi_theme_get_cursor_type( &wid, "txt", ROFI_CURSOR_DEFAULT), ROFI_CURSOR_TEXT);
+}
+END_TEST
START_TEST ( test_properties_list )
{
widget wid;
@@ -1376,6 +1398,13 @@ static Suite * theme_parser_suite (void)
suite_add_tcase(s, tc_prop_orientation );
}
{
+ TCase *tc_prop_cursor = tcase_create("Propertiescursor");
+ tcase_add_checked_fixture(tc_prop_cursor, theme_parser_setup, theme_parser_teardown);
+ tcase_add_test ( tc_prop_cursor, test_properties_cursor);
+ tcase_add_test ( tc_prop_cursor, test_properties_cursor_case );
+ suite_add_tcase(s, tc_prop_cursor );
+ }
+ {
TCase *tc_prop_list = tcase_create("Propertieslist");
tcase_add_checked_fixture(tc_prop_list, theme_parser_setup, theme_parser_teardown);
tcase_add_test ( tc_prop_list, test_properties_list);