Merge pull request #530 from DaveDavenport/themer

Themer
This commit is contained in:
Dave Davenport 2017-01-08 19:48:38 +01:00 committed by GitHub
commit 8fe5ea648a
41 changed files with 3353 additions and 784 deletions

View file

@ -4,7 +4,7 @@ before_script:
- add-apt-repository -y 'deb http://debian.jpleau.ca/ jessie-backports main contrib non-free' - add-apt-repository -y 'deb http://debian.jpleau.ca/ jessie-backports main contrib non-free'
- apt-get update -qq - apt-get update -qq
- apt-get install --force-yes -y autoconf automake make libx11-dev libpango1.0-dev libcairo2-dev libstartup-notification0-dev libxcb-icccm4-dev libxcb-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libx11-xcb-dev - apt-get install --force-yes -y autoconf automake make libx11-dev libpango1.0-dev libcairo2-dev libstartup-notification0-dev libxcb-icccm4-dev libxcb-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libx11-xcb-dev
- apt-get install --force-yes -y libxcb1-dev xvfb discount xdotool fluxbox libxkbcommon-dev libxkbcommon-x11-dev libxcb-ewmh-dev xutils-dev libtool lcov libxcb-randr0-dev doxygen python - apt-get install --force-yes -y libxcb1-dev xvfb discount xdotool fluxbox libxkbcommon-dev libxkbcommon-x11-dev libxcb-ewmh-dev xutils-dev libtool lcov libxcb-randr0-dev doxygen python flex bison
- git clone --recursive https://github.com/Airblader/xcb-util-xrm.git - git clone --recursive https://github.com/Airblader/xcb-util-xrm.git
- cd xcb-util-xrm - cd xcb-util-xrm
- ./autogen.sh --prefix=/usr - ./autogen.sh --prefix=/usr

View file

@ -9,6 +9,8 @@
* autoconf * autoconf
* automake (1.11.3 or up) * automake (1.11.3 or up)
* pkg-config * pkg-config
* flex
* bison
* Developer packages of the external libraries * Developer packages of the external libraries
### External libraries ### External libraries

View file

@ -3,9 +3,18 @@ AUTOMAKE_OPTIONS = 1.11.3
ACLOCAL_AMFLAGS = -I libgwater ${ACLOCAL_FLAGS} ACLOCAL_AMFLAGS = -I libgwater ${ACLOCAL_FLAGS}
AM_YFLAGS = -d
noinst_LIBRARIES = noinst_LIBRARIES =
include $(top_srcdir)/libgwater-xcb-nolibtool.mk include $(top_srcdir)/libgwater-xcb-nolibtool.mk
BUILT_SOURCES=\
lexer/theme-parser.h\
lexer/theme-parser.c\
lexer/theme-lexer.c
## ##
# Rofi the program # Rofi the program
## ##
@ -27,12 +36,13 @@ rofi_SOURCES=\
source/helper.c\ source/helper.c\
source/timings.c\ source/timings.c\
source/history.c\ source/history.c\
source/theme.c\
source/widgets/box.c\ source/widgets/box.c\
source/widgets/container.c\
source/widgets/widget.c\ source/widgets/widget.c\
source/widgets/textbox.c\ source/widgets/textbox.c\
source/widgets/listview.c\ source/widgets/listview.c\
source/widgets/scrollbar.c\ source/widgets/scrollbar.c\
source/widgets/separator.c\
source/xrmoptions.c\ source/xrmoptions.c\
source/x11-helper.c\ source/x11-helper.c\
source/dialogs/run.c\ source/dialogs/run.c\
@ -43,6 +53,8 @@ rofi_SOURCES=\
source/dialogs/window.c\ source/dialogs/window.c\
source/dialogs/script.c\ source/dialogs/script.c\
source/dialogs/help-keys.c\ source/dialogs/help-keys.c\
lexer/theme-parser.y\
lexer/theme-lexer.l\
include/xcb.h\ include/xcb.h\
include/xcb-internal.h\ include/xcb-internal.h\
include/rofi.h\ include/rofi.h\
@ -55,13 +67,14 @@ rofi_SOURCES=\
include/helper.h\ include/helper.h\
include/timings.h\ include/timings.h\
include/history.h\ include/history.h\
include/theme.h\
include/widgets/box.h\ include/widgets/box.h\
include/widgets/container.h\
include/widgets/widget.h\ include/widgets/widget.h\
include/widgets/widget-internal.h\ include/widgets/widget-internal.h\
include/widgets/textbox.h\ include/widgets/textbox.h\
include/widgets/listview.h\ include/widgets/listview.h\
include/widgets/scrollbar.h\ include/widgets/scrollbar.h\
include/widgets/separator.h\
include/xrmoptions.h\ include/xrmoptions.h\
include/x11-helper.h\ include/x11-helper.h\
include/dialogs/ssh.h\ include/dialogs/ssh.h\
@ -88,7 +101,8 @@ rofi_CFLAGS=\
-I$(top_srcdir)/config/\ -I$(top_srcdir)/config/\
-I$(top_builddir)/\ -I$(top_builddir)/\
-Werror=missing-prototypes\ -Werror=missing-prototypes\
-DSYSCONFDIR=\"$(sysconfdir)\" -DSYSCONFDIR=\"$(sysconfdir)\"\
-DTHEME_CONVERTER
rofi_LDADD=\ rofi_LDADD=\
$(glib_LIBS)\ $(glib_LIBS)\
@ -259,6 +273,13 @@ widget_test_LDADD=$(textbox_test_LDADD)
widget_test_CFLAGS=$(textbox_test_CFLAGS) widget_test_CFLAGS=$(textbox_test_CFLAGS)
widget_test_SOURCES=\ widget_test_SOURCES=\
source/widgets/widget.c\ source/widgets/widget.c\
source/widgets/textbox.c\
source/theme.c\
source/helper.c\
source/x11-helper.c\
config/config.c\
lexer/theme-parser.y\
lexer/theme-lexer.l\
test/widget-test.c test/widget-test.c
box_test_LDADD=$(textbox_test_LDADD) box_test_LDADD=$(textbox_test_LDADD)
@ -266,6 +287,10 @@ box_test_CFLAGS=$(textbox_test_CFLAGS)
box_test_SOURCES=\ box_test_SOURCES=\
source/widgets/widget.c\ source/widgets/widget.c\
source/widgets/box.c\ source/widgets/box.c\
lexer/theme-parser.y\
lexer/theme-lexer.l\
source/theme.c\
include/theme.h\
test/box-test.c test/box-test.c
scrollbar_test_LDADD=$(textbox_test_LDADD) scrollbar_test_LDADD=$(textbox_test_LDADD)
@ -273,11 +298,20 @@ scrollbar_test_CFLAGS=$(textbox_test_CFLAGS)
scrollbar_test_SOURCES=\ scrollbar_test_SOURCES=\
source/widgets/widget.c\ source/widgets/widget.c\
source/widgets/scrollbar.c\ source/widgets/scrollbar.c\
lexer/theme-parser.y\
lexer/theme-lexer.l\
source/theme.c\
include/theme.h\
test/scrollbar-test.c test/scrollbar-test.c
textbox_test_SOURCES=\ textbox_test_SOURCES=\
source/widgets/widget.c\ source/widgets/widget.c\
source/widgets/textbox.c\ source/widgets/textbox.c\
lexer/theme-parser.y\
lexer/theme-lexer.l\
source/theme.c\
source/helper.c\
source/x11-helper.c\
config/config.c\ config/config.c\
include/keyb.h\ include/keyb.h\
include/rofi.h\ include/rofi.h\

View file

@ -128,4 +128,5 @@ Settings config = {
.window_format = "{w} {c} {t}", .window_format = "{w} {c} {t}",
.click_to_exit = TRUE, .click_to_exit = TRUE,
.show_match = TRUE, .show_match = TRUE,
.theme = NULL,
}; };

View file

@ -3,6 +3,10 @@ AC_INIT([rofi], [1.3.1], [https://github.com/DaveDavenport/rofi/],[],[https://fo
AC_CONFIG_SRCDIR([source/rofi.c]) AC_CONFIG_SRCDIR([source/rofi.c])
AC_CONFIG_HEADER([config.h]) AC_CONFIG_HEADER([config.h])
AC_PROG_LEX
AC_PROG_YACC
dnl --------------------------------------------------------------------- dnl ---------------------------------------------------------------------
dnl Setup automake to be silent and in foreign mode. dnl Setup automake to be silent and in foreign mode.
dnl We want xz distribution dnl We want xz distribution

View file

@ -135,6 +135,8 @@ Global options:
True (Default) True (Default)
-[no-]show-match Indicate how it match by underlining it. -[no-]show-match Indicate how it match by underlining it.
True (Default) True (Default)
-theme [string] New style theme file
(unset) (Default)
-pid [string] Pidfile location -pid [string] Pidfile location
/tmp/rofi.pid (File) /tmp/rofi.pid (File)
-kb-primary-paste [string] Paste primary selection -kb-primary-paste [string] Paste primary selection

View file

@ -98,6 +98,8 @@ rofi.window-format: w c t
! rofi.click-to-exit: true ! rofi.click-to-exit: true
! "Indicate how it match by underlining it." Set from: Default ! "Indicate how it match by underlining it." Set from: Default
! rofi.show-match: true ! rofi.show-match: true
! "New style theme file" Set from: Default
! rofi.theme:
! "Pidfile location" Set from: File ! "Pidfile location" Set from: File
rofi.pid: /tmp/rofi.pid rofi.pid: /tmp/rofi.pid
! "Paste primary selection" Set from: File ! "Paste primary selection" Set from: File

172
doc/themer.md Normal file
View file

@ -0,0 +1,172 @@
# Basic Organization
Each widget has:
## Name
Name: Internal name of the widget.
Sub-widgets are {Parent}.{Child}.
Example: window, window.mainbox.listview, window.mainbox.listview.element
Names are prefixed with a `#`
List of names in **rofi**:
* `#window`
* `#window.overlay`: The overlay widget.
* `#window.mainbox`
* `#window.mainbox.box`: The main vertical @box
* `#window.mainbox.inputbar`
* `#window.mainbox.inputbar.box`: The horizontal @box packing the widgets.
* `#window.mainbox.inputbar.case-indicator`: The case/sort indicator @textbox
* `#window.mainbox.inputbar.prompt`: The prompt @textbox
* `#window.mainbox.inputbar.entry`: The main entry @textbox
* `#window.mainbox.listview`
* `#window.mainbox.listview.box`: The listview container.
* `#window.mainbox.listview.scrollbar`: The listview scrollbar
* `#window.mainbox.listview.element`: The entries in the listview
* `#window.mainbox.sidebar`
* `#window.mainbox.sidebar.box`: The main horizontal @box packing the buttons.
* `#window.mainbox.sidebar.button`: The buttons @textbox for each mode.
* `#window.mainbox.message`
* `#window.mainbox.message.textbox`: The message textbox.
* `#window.mainbox.message.box`: The box containing the message.
## State
State: State of widget
Optional flag(s) indicating state.
These are appended after the name or class of the widget.
`#window.mainbox.sidebar.button selected.normal { }`
`#window.mainbox.listview.element selected.urgent { }`
Currently only the entrybox and scrollbar has states:
`{visible modifier}.{state}`
Where `visible modifier` can be:
* normal: No modification.
* selected: The entry is selected/highlighted by user.
* alternate: The entry is at an alternating row. (uneven row)
Where `state` is:
* normal: No modification.
* urgent: This entry is marked urgent.
* activE: This entry is marked active.
These can be mixed.
Example:
```
#name.to.textbox selected.active {
background: #003642;
foreground: #008ed4;
}
```
Sets all selected textboxes marked active to the given foreground and background color.
The scrollbar when drawing uses the `handle` state when drawing the small scrollbar handle.
Allowing overriding of color.
# File structure
The file is structured as follows
```
/* Global properties, that apply as default to all widgets. */
{list of properties}
#{name} {optional state} {
{list of properties}
}
#{name}.{optional state} {
{list of properties}
}
```
The global properties an freeĺy be mixed between entries.
Name and state can be separated by a comman, or joined using a dot.
Each property is constructed like:
```
{key} : {value} ;
```
Key is a simple ascii string.
Separated from value by a colon ':';
Value supports the following formats:
* string: `"{string}"`
* integer: `[0-9]+`
* double: `[0-9]+\.[0-9]`
* boolean: `true|false`
* color:
* `#[0-9a-fA-F]{6}`: hexidecimal rgb color.
* `#[0-9a-fA-F]{8}`: hexidecimal argb color.
* `argb:[0-0a-fA-F]{8}`: Old **rofi** argb color style.
* `rgba\([0-9]{1,3},[0-9]{1,3}, [0-9]{1,3}, {double}\)`: css style rgba color.
* `rgb\([0-9]{1,3},[0-9]{1,3}, [0-9]{1,3}\)`: css style rgb color.
* distance:
* `{size}{unit} {line-style}`
* unit can be px,em,%. for px `{size}` is an integer number, for %,em it is a positive real.
* {line-style} can be `dash` or `solid` and is optional.
* padding: `({distance}){1,4}`
* position: (center|north|south|east|west|northeast|northwest|southwest|southeast)
Each property is closed by a semi-colon `;`;
The following properties are currently supports:
* all widgets:
* padding: distance
* margin: distance
* border: distance
* background: color
* foreground: color
* end: boolean
* window:
* font: string
* transparency: string
- real
- background
- screenshot
- Path to png file
* position: position
The place of the anchor on the monitor.
* anchor: anchor
The anchor position on the window.
* scrollbar
* foreground: color
* handle-width: distance
* handle-color: color
* foreground: color
* box
* spacing: distance
* textbox:
* background: color
* foreground: color
* listview:
* columns: integer
* fixed-height: boolean
* dynamic: boolean
* scrollbar: boolean
* scrollbar-width: distance
* cycle: boolean
* spacing: distance
## Resolving properties
It tries to find the longest match down the dependency tree.

View file

@ -82,6 +82,14 @@ int find_arg_int ( const char * const key, int *val );
*/ */
int find_arg_str ( const char * const key, char** val ); int find_arg_str ( const char * const key, char** val );
/**
* @param key The key to search for
*
* Parse all command line options 'key' to string vector.
*
* @returns str vector. user should free array.
*/
const char ** find_arg_strv ( const char *const key );
/** /**
* @param key The key to search for * @param key The key to search for
* *

View file

@ -38,7 +38,7 @@ typedef enum
/** Middle right */ /** Middle right */
WL_EAST = 4, WL_EAST = 4,
/** Bottom right */ /** Bottom right */
WL_EAST_SOUTH = 5, WL_SOUTH_EAST = 5,
/** Bottom middle */ /** Bottom middle */
WL_SOUTH = 6, WL_SOUTH = 6,
/** Bottom left */ /** Bottom left */
@ -149,6 +149,8 @@ typedef struct
/** Click outside the window to exit */ /** Click outside the window to exit */
int click_to_exit; int click_to_exit;
gboolean show_match; gboolean show_match;
char *theme;
} Settings; } Settings;
/** Global Settings structure. */ /** Global Settings structure. */
extern Settings config; extern Settings config;

337
include/theme.h Normal file
View file

@ -0,0 +1,337 @@
#ifndef THEME_H
#define THEME_H
#include <glib.h>
#include <cairo.h>
#include <widgets/widget.h>
#include <settings.h>
/** Style of line */
typedef enum {
/** Solid line */
SOLID,
/** Dashed line */
DASH
} LineStyle;
/**
* Distance unit type.
*/
typedef enum {
/** PixelWidth in pixels. */
PW_PX,
/** PixelWidth in EM. */
PW_EM,
/** PixelWidget in percentage */
PW_PERCENT,
} PixelWidth;
/**
* Structure representing a distance.
*/
typedef struct {
/** Distance */
double distance;
/** Unit type of the distance */
PixelWidth type;
/** Style of the line */
LineStyle style;
} Distance;
/**
* Type of orientation.
*/
typedef enum {
ORIENTATION_VERTICAL,
ORIENTATION_HORIZONTAL
} Orientation;
/**
* Type of property
*/
typedef enum {
/** Integer */
P_INTEGER,
/** Double */
P_DOUBLE,
/** String */
P_STRING,
/** Boolean */
P_BOOLEAN,
/** Color */
P_COLOR,
/** Padding */
P_PADDING,
/** Link to global setting */
P_LINK,
/** Position */
P_POSITION,
} PropertyType;
/**
* Represent the color in theme.
*/
typedef struct
{
/** red channel */
double red;
/** green channel */
double green;
/** blue channel */
double blue;
/** alpha channel */
double alpha;
} ThemeColor;
/**
* Padding
*/
typedef struct
{
Distance top;
Distance right;
Distance bottom;
Distance left;
} Padding;
/**
* Property structure.
*/
typedef struct Property {
/** Name of property */
char *name;
/** Type of property. */
PropertyType type;
/** Value */
union {
/** integer */
int i;
/** Double */
double f;
/** String */
char *s;
/** boolean */
gboolean b;
/** Color */
ThemeColor color;
/** Padding */
Padding padding;
/** Reference */
struct {
/** Name */
char *name;
/** Cached looked up ref */
struct Property *ref;
} link;
} value;
} Property;
/**
* ThemeWidget.
*/
typedef struct ThemeWidget {
int set;
char *name;
unsigned int num_widgets;
struct ThemeWidget **widgets;
GHashTable *properties;
struct ThemeWidget *parent;
} ThemeWidget;
/**
* Global pointer to the current active theme.
*/
extern ThemeWidget *rofi_theme;
/**
* @param base Handle to the current level in the theme.
* @param name Name of the new element.
*
* Create a new element in the theme structure.
*
* @returns handle to the new entry.
*/
ThemeWidget *rofi_theme_find_or_create_name ( ThemeWidget *base, const char *name );
/**
* @param widget The widget handle.
*
* Print out the widget to the commandline.
*/
void rofi_theme_print ( ThemeWidget *widget );
/**
* @param type The type of the property to create.
*
* Create a theme property of type.
*
* @returns a new property.
*/
Property *rofi_theme_property_create ( PropertyType type );
/**
* @param p The property to free.
*
* Free the content of the property.
*/
void rofi_theme_property_free ( Property *p );
/**
* @param wid
*
* Free the widget and alll children.
*/
void rofi_theme_free ( ThemeWidget *wid );
/**
* @param file filename to parse.
*
* Parse the input theme file.
*
* @returns returns TRUE when error.
*/
gboolean rofi_theme_parse_file ( const char *file );
/**
* @param string to parse.
*
* Parse the input string in addition to theme file.
*
* @returns returns TRUE when error.
*/
gboolean rofi_theme_parse_string ( const char *string );
/**
* @param widget The widget handle.
* @param table HashTable containing properties set.
*
* Merge properties with widgets current property.
*/
void rofi_theme_widget_add_properties ( ThemeWidget *widget, GHashTable *table );
/**
* Public API
*/
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the distance of the widget.
*
* @returns The distance value of this property for this widget.
*/
Distance rofi_theme_get_distance ( const widget *widget, const char *property, int def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the integer of the widget.
*
* @returns The integer value of this property for this widget.
*/
int rofi_theme_get_integer ( const widget *widget, const char *property, int def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the position of the widget.
*
* @returns The position value of this property for this widget.
*/
int rofi_theme_get_position ( const widget *widget, const char *property, int def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the integer of the widget.
*
* @returns The integer value of this property for this widget.
*/
int rofi_theme_get_integer_exact ( const widget *widget, const char *property, int def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the boolean of the widget.
*
* @returns The boolean value of this property for this widget.
*/
int rofi_theme_get_boolean ( const widget *widget, const char *property, int def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the string of the widget.
*
* @returns The string value of this property for this widget.
*/
char *rofi_theme_get_string ( const widget *widget, const char *property, char *def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param def The default value.
*
* Obtain the padding of the widget.
*
* @returns The double value of this property for this widget.
*/
double rofi_theme_get_double ( const widget *widget, const char *property, double def );
/**
* @param widget The widget to query
* @param property The property to query.
* @param d The drawable to apply color.
*
* Obtain the color of the widget and applies this to the drawable d.
*
*/
void rofi_theme_get_color ( const widget *widget, const char *property, cairo_t *d);
/**
* @param widget The widget to query
* @param property The property to query.
* @param pad The default value.
*
* Obtain the padding of the widget.
*
* @returns The padding of this property for this widget.
*/
Padding rofi_theme_get_padding ( const widget *widget, const char *property, Padding pad );
/**
* @param d The distance handle.
* @param ori The orientation.
*
* Convert Distance into pixels.
* @returns the number of pixels this distance represents.
*/
int distance_get_pixel ( Distance d, Orientation ori );
/**
* @param d The distance handle.
* @param draw The cairo drawable.
*
* Set linestyle.
*/
void distance_get_linestyle ( Distance d, cairo_t *draw );
#ifdef THEME_CONVERTER
/**
* Function to convert old theme into new theme format.
*/
void rofi_theme_convert_old_theme ( void );
#endif
#endif

View file

@ -1,12 +1,13 @@
#ifndef ROFI_VIEW_INTERNAL_H #ifndef ROFI_VIEW_INTERNAL_H
#define ROFI_VIEW_INTERNAL_H #define ROFI_VIEW_INTERNAL_H
#include "widgets/container.h"
#include "widgets/widget.h" #include "widgets/widget.h"
#include "widgets/textbox.h" #include "widgets/textbox.h"
#include "widgets/separator.h"
#include "widgets/listview.h" #include "widgets/listview.h"
#include "widgets/box.h" #include "widgets/box.h"
#include "keyb.h" #include "keyb.h"
#include "x11-helper.h" #include "x11-helper.h"
#include "theme.h"
/** /**
* @ingroup ViewHandle * @ingroup ViewHandle
@ -22,7 +23,8 @@ struct RofiViewState
/** Flag indicating if view needs to be refiltered. */ /** Flag indicating if view needs to be refiltered. */
int refilter; int refilter;
/** Widget representing the main container. */
container *main_window;
/** Main #box widget holding different elements. */ /** Main #box widget holding different elements. */
box *main_box; box *main_box;
/** #box widget packing the input bar widgets. */ /** #box widget packing the input bar widgets. */
@ -33,8 +35,6 @@ struct RofiViewState
textbox *text; textbox *text;
/** #textbox showing the state of the case sensitive and sortng. */ /** #textbox showing the state of the case sensitive and sortng. */
textbox *case_indicator; textbox *case_indicator;
/** #separator widget below the input bar. */
separator *input_bar_separator;
/** #listview holding the displayed elements. */ /** #listview holding the displayed elements. */
listview *list_view; listview *list_view;
@ -63,8 +63,6 @@ struct RofiViewState
unsigned int selected_line; unsigned int selected_line;
/** The return state of the view */ /** The return state of the view */
MenuReturn retv; MenuReturn retv;
/** Calculated border width */
unsigned int border;
/** Monitor #workarea the view is displayed on */ /** Monitor #workarea the view is displayed on */
workarea mon; workarea mon;

View file

@ -111,12 +111,6 @@ unsigned int rofi_view_get_selected_line ( const RofiViewState *state );
*/ */
void rofi_view_restart ( RofiViewState *state ); void rofi_view_restart ( RofiViewState *state );
/**
* @param state The handle to the view
*
* Update the state of the view. This involves filter state.
*/
void rofi_view_update ( RofiViewState *state );
/** /**
* @param state The handle to the view * @param state The handle to the view
@ -254,5 +248,12 @@ void rofi_view_workers_initialize ( void );
* Stop all threads and free the resources used by the threadpool * Stop all threads and free the resources used by the threadpool
*/ */
void rofi_view_workers_finalize ( void ); void rofi_view_workers_finalize ( void );
/**
* Return the current monitor workarea.
*
* @returns the current monitor workarea
*/
void rofi_view_get_current_monitor ( int *width, int *height );
/**@}*/ /**@}*/
#endif #endif

View file

@ -32,42 +32,31 @@ typedef enum
} boxType; } boxType;
/** /**
* @param name The name of the widget.
* @param type The packing direction of the newly created box. * @param type The packing direction of the newly created box.
* @param x The x position of the box relative to its parent.
* @param y The y position of the box relative to its parent.
* @param w The width of the box.
* @param h The height of the box.
* *
* @returns a newly created box, free with #widget_free * @returns a newly created box, free with #widget_free
*/ */
box * box_create ( boxType type, short x, short y, short w, short h ); box * box_create ( const char *name, boxType type );
/** /**
* @param box Handle to the box widget. * @param box Handle to the box widget.
* @param child Handle to the child widget to pack. * @param child Handle to the child widget to pack.
* @param expand If the child widget should expand and use all available space. * @param expand If the child widget should expand and use all available space.
* @param end If the child widget should be packed at the end. * @param index The position index.
* *
* Add a widget to the box. * Add a widget to the box.
*/ */
void box_add ( box *box, widget *child, gboolean expand, gboolean end ); void box_add ( box *box, widget *child, gboolean expand, int index );
/** /**
* @param box Handle to the box widget. * @param box Handle to the box widget.
* *
* Obtains the minimal size required to display all widgets. (expanding widgets are not counted, except for their * Obtains the minimal size required to display all widgets. (expanding widgets are not counted, except for their
* padding) * spacing)
* *
* @returns the minimum size in pixels. * @returns the minimum size in pixels.
*/ */
int box_get_fixed_pixels ( box *box ); int box_get_fixed_pixels ( box *box );
/**
* @param box Handle to the box widget.
* @param padding The padding to apply.
*
* Set the padding to apply between the children in pixels.
*/
void box_set_padding ( box * box, unsigned int padding );
/*@}*/ /*@}*/
#endif // ROFI_HBOX_H #endif // ROFI_HBOX_H

View file

@ -0,0 +1,34 @@
#ifndef ROFI_CONTAINER_H
#define ROFI_CONTAINER_H
#include "widget.h"
/**
* @defgroup container container
* @ingroup widget
*
*
* @{
*/
/**
* Abstract handle to the container widget internal state.
*/
typedef struct _window container;
/**
* @param name The name of the widget.
*
* @returns a newly created container, free with #widget_free
*/
container * container_create ( const char *name );
/**
* @param container Handle to the container widget.
* @param child Handle to the child widget to pack.
*
* Add a widget to the container.
*/
void container_add ( container *container, widget *child );
/*@}*/
#endif // ROFI_CONTAINER_H

View file

@ -42,13 +42,15 @@ typedef void ( *listview_update_callback )( textbox *tb, unsigned int entry, voi
typedef void ( *listview_mouse_activated_cb )( listview *, xcb_button_press_event_t *, void * ); typedef void ( *listview_mouse_activated_cb )( listview *, xcb_button_press_event_t *, void * );
/** /**
* @param name The name of the to be created widget.
* @param cb The update callback. * @param cb The update callback.
* @param udata The user data to pass to the callback * @param udata The user data to pass to the callback
* @param eh The height of one element * @param eh The height of one element
* @param reverse Reverse the listview order.
* *
* @returns a new listview * @returns a new listview
*/ */
listview *listview_create ( listview_update_callback cb, void *udata, unsigned int eh ); listview *listview_create ( const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse );
/** /**
* @param lv The listview handle * @param lv The listview handle
@ -75,15 +77,6 @@ void listview_set_selected ( listview *lv, unsigned int selected );
*/ */
unsigned int listview_get_selected ( listview *lv ); unsigned int listview_get_selected ( listview *lv );
/**
* @param lv The listview handle
*
* Get the desired height of the listview widget.
*
* @returns the desired height.
*/
unsigned int listview_get_desired_height ( listview *lv );
/** /**
* @param lv The listview handle * @param lv The listview handle
* *
@ -131,44 +124,13 @@ void listview_nav_page_next ( listview *lv );
*/ */
void listview_nav_page_prev ( listview *lv ); void listview_nav_page_prev ( listview *lv );
/**
* @param lv Handler to the listview object
* @param padding The padding
*
* Padding on between the widgets.
*/
void listview_set_padding ( listview *lv, unsigned int padding );
/**
* @param lv Handler to the listview object
* @param lines The maximum number of lines
*
* Set the maximum number of lines to show.
*/
void listview_set_max_lines ( listview *lv, unsigned int lines );
/**
* @param lv Handler to the listview object
* @param columns The maximum number of columns
*
* Set the maximum number of columns to show.
*/
void listview_set_max_columns ( listview *lv, unsigned int columns );
/**
* @param lv Handler to the listview object
* @param enabled enable
*
* Set fixed num lines mode.
*/
void listview_set_fixed_num_lines ( listview *lv, gboolean enabled );
/** /**
* @param lv Handler to the listview object * @param lv Handler to the listview object
* @param enabled enable * @param enabled enable
* *
* Hide the scrollbar. * Hide the scrollbar.
*/ */
void listview_set_hide_scrollbar ( listview *lv, gboolean enabled ); void listview_set_show_scrollbar ( listview *lv, gboolean enabled );
/** /**
* @param lv Handler to the listview object * @param lv Handler to the listview object
* @param width Width in pixels * @param width Width in pixels
@ -207,6 +169,47 @@ void listview_set_mouse_activated_cb ( listview *lv, listview_mouse_activated_cb
* Enable,disable multi-select. * Enable,disable multi-select.
*/ */
void listview_set_multi_select ( listview *lv, gboolean enable ); void listview_set_multi_select ( listview *lv, gboolean enable );
/**
* @param lv Handler to the listview object.
* @param num_lines the maximum number of lines to display.
*
* Set the maximum number of lines to display.
*/
void listview_set_num_lines ( listview *lv, unsigned int num_lines );
/**
* @param lv Handler to the listview object.
*
* Get the maximum number of lines to display.
*
* @returns get the numger of lines to display.
*/
unsigned int listview_get_num_lines ( listview *lv );
/**
* @param lv Handler to the listview object.
*
* Get the fixed-height property.
*
* @returns get fixed-height.
*/
gboolean listview_get_fixed_num_lines ( listview *lv );
/**
* @param lv Handler to the listview object.
*
* Set fixed num lines mode.
*/
void listview_set_fixed_num_lines ( listview *lv );
/**
* @param lv Handler to the listview object.
* @param max_lines the maximum number of lines to display.
*
* Set the maximum number of lines to display.
*/
void listview_set_max_lines ( listview *lv, unsigned int max_lines );
/* @} */ /* @} */
#endif // ROFI_LISTVIEW_H #endif // ROFI_LISTVIEW_H

View file

@ -19,19 +19,17 @@ typedef struct _scrollbar
unsigned int length; unsigned int length;
unsigned int pos; unsigned int pos;
unsigned int pos_length; unsigned int pos_length;
Distance width;
} scrollbar; } scrollbar;
/** /**
* @param x The x coordinate (relative to parent) to position the new scrollbar * @param name The name of the widget.
* @param y The y coordinate (relative to parent) to position the new scrollbar
* @param w The width of the scrollbar
* @param h The height of the scrollbar
* *
* Create a new scrollbar * Create a new scrollbar
* *
* @returns the scrollbar object. * @returns the scrollbar object.
*/ */
scrollbar *scrollbar_create ( short x, short y, short w, short h ); scrollbar *scrollbar_create ( const char *name );
/** /**
* @param sb scrollbar object * @param sb scrollbar object

View file

@ -1,65 +0,0 @@
#ifndef ROFI_SEPARATOR_H
#define ROFI_SEPARATOR_H
#include <cairo.h>
#include "widget.h"
/**
* @defgroup separator separator
* @ingroup widget
*
* Displays a horizontal separator line. The height of the widget determines the line width.
*
* @{
*/
/**
* Abstract handle to the separator widget internal state.
*/
typedef struct _separator separator;
/**
* Direction of the separator.
*/
typedef enum
{
S_HORIZONTAL = 0,
S_VERTICAL = 1
} separator_type;
/**
* The style of the separator line.
*/
typedef enum
{
S_LINE_NONE,
S_LINE_SOLID,
S_LINE_DASH
} separator_line_style;
/**
* @param type The type of separator.
* @param sw The thickness of the separator.
*
* Create a horizontal separator with height h.
*
* @returns a new separator, free with ::widget_free
*/
separator *separator_create ( separator_type type, short sw );
/**
* @param sp The separator widget handle.
* @param style_str String representation of the style.
*
* Sets the line style based on the string style_str
*/
void separator_set_line_style_from_string ( separator *sp, const char *style_str );
/**
* @param sp The separator widget handle.
* @param style The new style.
*
* Sets the line style.
*/
void separator_set_line_style ( separator *sp, separator_line_style style );
/*@}*/
#endif // ROFI_SEPARATOR_H

View file

@ -39,6 +39,8 @@ typedef struct
int update; int update;
int blink; int blink;
guint blink_timeout; guint blink_timeout;
//
const char *theme_name ;
} textbox; } textbox;
/** /**
@ -84,11 +86,8 @@ typedef enum
} TextBoxFontType; } TextBoxFontType;
/** /**
* @param name The name of the to be created widget.
* @param flags #TextboxFlags indicating the type of textbox. * @param flags #TextboxFlags indicating the type of textbox.
* @param x horizontal positon of textbox
* @param y vertical position of textbox
* @param w width of textbox
* @param h height of textbox
* @param tbft #TextBoxFontType current state of textbox. * @param tbft #TextBoxFontType current state of textbox.
* @param text intial text to display. * @param text intial text to display.
* *
@ -97,8 +96,7 @@ typedef enum
* free with #widget_free * free with #widget_free
* @returns a new #textbox * @returns a new #textbox
*/ */
textbox* textbox_create ( TextboxFlags flags, textbox* textbox_create ( const char *name, TextboxFlags flags,
short x, short y, short w, short h,
TextBoxFontType tbft, TextBoxFontType tbft,
const char *text ); const char *text );
/** /**
@ -200,6 +198,13 @@ int textbox_get_font_width ( const textbox *tb );
*/ */
double textbox_get_estimated_char_width ( void ); double textbox_get_estimated_char_width ( void );
/**
* Estimate the height of a character.
*
* @returns the height of a character in pixels.
*/
double textbox_get_estimated_char_height ( void );
/** /**
* @param tb Handle to the textbox * @param tb Handle to the textbox
* @param pos The start position * @param pos The start position
@ -220,12 +225,17 @@ void textbox_delete ( textbox *tb, int pos, int dlen );
* TODO remove for #widget_resize and #widget_move * TODO remove for #widget_resize and #widget_move
*/ */
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h ); void textbox_moveresize ( textbox *tb, int x, int y, int w, int h );
/** /**
* @param tb Handle to the textbox
* @param eh The number of rows to display
*
* Get the (estimated) with of a character, can be used to calculate window width. * Get the (estimated) with of a character, can be used to calculate window width.
* This includes padding.
* *
* @returns the estimated width of a character. * @returns the estimated width of a character.
*/ */
int textbox_get_estimated_char_height ( void ); int textbox_get_estimated_height ( const textbox *tb, int eh );
/** /**
* @param p The new default PangoContext * @param p The new default PangoContext
* *

View file

@ -1,6 +1,7 @@
#ifndef WIDGET_INTERNAL_H #ifndef WIDGET_INTERNAL_H
#define WIDGET_INTERNAL_H #define WIDGET_INTERNAL_H
#include "theme.h"
/** /**
* Data structure holding the internal state of the Widget * Data structure holding the internal state of the Widget
*/ */
@ -14,10 +15,17 @@ struct _widget
short w; short w;
/** Height of the widget */ /** Height of the widget */
short h; short h;
/** Padding */
Padding margin;
Padding padding;
Padding border;
/** enabled or not */ /** enabled or not */
gboolean enabled; gboolean enabled;
/** Expand the widget when packed */ /** Expand the widget when packed */
gboolean expand; gboolean expand;
/*** The packing index */
int index;
/** Place widget at end of parent */ /** Place widget at end of parent */
gboolean end; gboolean end;
/** Parent widget */ /** Parent widget */
@ -38,6 +46,8 @@ struct _widget
/** Handle mouse motion, used for dragging */ /** Handle mouse motion, used for dragging */
gboolean ( *motion_notify )( struct _widget *, xcb_motion_notify_event_t * ); gboolean ( *motion_notify )( struct _widget *, xcb_motion_notify_event_t * );
int (*get_desired_height) ( struct _widget * );
/** widget clicked callback */ /** widget clicked callback */
widget_clicked_cb clicked; widget_clicked_cb clicked;
/** user data for clicked callback */ /** user data for clicked callback */
@ -45,5 +55,95 @@ struct _widget
/** Free widget callback */ /** Free widget callback */
void ( *free )( struct _widget *widget ); void ( *free )( struct _widget *widget );
/** Name of widget (used for theming) */
char *name;
const char *state;
}; };
/**
* @param widget The widget to initialize.
* @param name The name of the widget.
*
* Initializes the widget structure.
*
*/
void widget_init ( widget *widget , const char *name );
/**
* @param widget The widget handle.
* @param state The state of the widget.
*
* Set the state of the widget.
*/
void widget_set_state ( widget *widget, const char *state );
/**
* @param wid The widget handle.
*
* Get the left padding of the widget.
*
* @returns the left padding in pixels.
*/
int widget_padding_get_left ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get the right padding of the widget.
*
* @returns the right padding in pixels.
*/
int widget_padding_get_right ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get the top padding of the widget.
*
* @returns the top padding in pixels.
*/
int widget_padding_get_top ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get the bottom padding of the widget.
*
* @returns the bottom padding in pixels.
*/
int widget_padding_get_bottom ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get width of the content of the widget
*
* @returns the widget width, excluding padding.
*/
int widget_padding_get_remaining_width ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get height of the content of the widget
*
* @returns the widget height, excluding padding.
*/
int widget_padding_get_remaining_height ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get the combined top and bottom padding.
*
* @returns the top and bottom padding of the widget in pixels.
*/
int widget_padding_get_padding_height ( const widget *wid );
/**
* @param wid The widget handle.
*
* Get the combined left and right padding.
*
* @returns the left and right padding of the widget in pixels.
*/
int widget_padding_get_padding_width ( const widget *wid );
#endif // WIDGET_INTERNAL_H #endif // WIDGET_INTERNAL_H

View file

@ -173,5 +173,24 @@ void widget_set_clicked_handler ( widget *wid, widget_clicked_cb cb, void *udata
* returns TRUE when handled. * returns TRUE when handled.
*/ */
gboolean widget_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ); gboolean widget_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme );
/**
* @param wid The widget handle
* @param name The name of the widget.
*
* Set name on widget.
*/
void widget_set_name ( widget *wid, const char *name );
/**
* @param wid The widget handle
*
* Get the desired height of this widget recursively.
*
* @returns the desired height of the widget in pixels.
*/
int widget_get_desired_height ( widget *wid );
/*@}*/ /*@}*/
#endif // ROFI_WIDGET_H #endif // ROFI_WIDGET_H

336
lexer/theme-lexer.l Normal file
View file

@ -0,0 +1,336 @@
%option noyywrap nounput never-interactive
%option bison-locations
%{
#include <stdio.h>
#include "lexer/theme-parser.h"
int last_state = 0;
GQueue *queue = NULL;
%}
%{
int str_len = 0;
char *input_str = NULL;
#define YY_INPUT(buf,result,max_size) \
{\
if ( input_str == NULL ) { \
errno =0; \
while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
break; \
} \
errno=0; \
clearerr(yyin); \
} \
} else {\
yy_size_t len = MIN (max_size, str_len);\
if ( len > 0 ){\
memcpy (buf, input_str, len);\
input_str+=len;\
str_len-=len;\
result = len;\
} else {\
result = YY_NULL;\
} \
}\
}
#define YY_USER_ACTION {\
yylloc->last_column+= yyleng;\
}
#define YY_LLOC_START {\
yylloc->first_line = yylloc->last_line;\
yylloc->first_column = yylloc->last_column;\
}
%}
WHITESPACE [[:blank:]]
WORD [[:alnum:]-]+
STRING [[:print:]]+
HEX [[:xdigit:]]
NUMBER [[:digit:]]
REAL [[:digit:]]+(\.[[:digit:]]+)?
PX (px)
EM (em)
PERCENT (\%)
ASTERIX \*
CENTER "center"
NORTH "north"
SOUTH "south"
EAST "east"
WEST "west"
LS_DASH "dash"
LS_SOLID "solid"
%x PROPERTIES
%x NAMESTR
%x ENTRY
%x DEFAULTS
%%
%{
YY_LLOC_START
%}
%{
if ( queue == NULL ){
queue = g_queue_new ( );
}
%}
<*>"//" {
int c;
while ((c = input()) != EOF){
if (c == '\n') {
yylloc->last_column = 1;
yylloc->last_line ++;
break;
}
yylloc->last_column++;
}
YY_LLOC_START
}
<*>"/*" {
int c = 0, p;
int nesting_depth = 1;
while (nesting_depth) {
p = c;
c = input();
switch (c) {
case '*': yylloc->last_column++; if (p == '/') { c = 0; nesting_depth++; } break;
case '/': yylloc->last_column++; if (p == '*') { c = 0; nesting_depth--; } break;
case '\n': {
yylloc->last_column = 1;
yylloc->last_line ++;
break;
}
case EOF: nesting_depth = 0; break;
default:
yylloc->last_column++;
;
}
}
YY_LLOC_START
}
<INITIAL>{ASTERIX} {
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
BEGIN(DEFAULTS);
return PDEFAULTS;
}
<DEFAULTS>{WHITESPACE} {}
<DEFAULTS>"\{" {
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
BEGIN(ENTRY);
return BOPEN;
}
/* Go into parsing an entry */
<NAMESTR>"\{" {
g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) );
BEGIN(ENTRY);
return BOPEN;
}
/* Pop out of parsing an entry. */
<ENTRY>"\}" {
g_queue_pop_head ( queue );
BEGIN(GPOINTER_TO_INT(g_queue_pop_head ( queue )));
return BCLOSE;
}
<INITIAL>"#" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(NAMESTR);return NAME_PREFIX;}
<NAMESTR>\.|{WHITESPACE} { return NSEP; }
<ENTRY>{WORD} { yylval->sval = g_strdup(yytext); return N_STRING;}
<NAMESTR>{WORD} { yylval->sval = g_strdup(yytext); return NAME_ELEMENT;}
/* After Namestr/Classstr we want to go to state str, then to { */
/*<NAMESTR>{WHITESPACE} { BEGIN(GPOINTER_TO_INT (g_queue_pop_head ( queue )));}*/
<INITIAL,ENTRY>{WHITESPACE}+ ; // ignore all whitespace
<PROPERTIES>{WHITESPACE}+ ; // ignore all whitespace
<INITIAL,ENTRY>":" { g_queue_push_head ( queue, GINT_TO_POINTER (YY_START) ); BEGIN(PROPERTIES); return PSEP; }
<PROPERTIES>";" { BEGIN(GPOINTER_TO_INT ( g_queue_pop_head ( queue ))); return PCLOSE;}
<PROPERTIES>(true|false) { yylval->bval= g_strcmp0(yytext, "true") == 0; return T_BOOLEAN;}
<PROPERTIES>{NUMBER}+ { yylval->ival = (int)g_ascii_strtoll(yytext, NULL, 10); return T_INT;}
<PROPERTIES>{NUMBER}+\.{NUMBER}+ { yylval->fval = g_ascii_strtod(yytext, NULL); return T_DOUBLE;}
<PROPERTIES>\"{STRING}\" { yytext[yyleng-1] = '\0'; yylval->sval = g_strdup(&yytext[1]); return T_STRING;}
<PROPERTIES>@{WORD} {
yylval->sval = g_strdup(yytext);
return T_LINK;
}
<PROPERTIES>{REAL}{EM} {
yylval->distance.distance = (double)g_ascii_strtod(yytext, NULL);
yylval->distance.type = PW_EM;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{NUMBER}+{PX} {
yylval->distance.distance = (double)g_ascii_strtoll(yytext, NULL, 10);
yylval->distance.type = PW_PX;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{NUMBER}+{PX}{WHITESPACE}{LS_DASH} {
yylval->distance.distance = (double)g_ascii_strtoll(yytext, NULL, 10);
yylval->distance.type = PW_PX;
yylval->distance.style = DASH;
return T_PIXEL;
}
<PROPERTIES>{NUMBER}+{EM}{WHITESPACE}{LS_DASH} {
yylval->distance.distance = (double)g_ascii_strtoll(yytext, NULL, 10);
yylval->distance.type = PW_PX;
yylval->distance.style = DASH;
return T_PIXEL;
}
<PROPERTIES>{NUMBER}+{PX}{WHITESPACE}{LS_SOLID} {
yylval->distance.distance = (double)g_ascii_strtoll(yytext, NULL, 10);
yylval->distance.type = PW_PX;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{NUMBER}+{EM}{WHITESPACE}{LS_SOLID} {
yylval->distance.distance = (double)g_ascii_strtoll(yytext, NULL, 10);
yylval->distance.type = PW_PX;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{REAL}{PERCENT} {
yylval->distance.distance = (double)g_ascii_strtod(yytext, NULL);
yylval->distance.type = PW_PERCENT;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{REAL}{PERCENT}{WHITESPACE}{LS_SOLID} {
yylval->distance.distance = (double)g_ascii_strtod(yytext, NULL);
yylval->distance.type = PW_PERCENT;
yylval->distance.style = SOLID;
return T_PIXEL;
}
<PROPERTIES>{REAL}{PERCENT}{WHITESPACE}{LS_DASH} {
yylval->distance.distance = (double)g_ascii_strtod(yytext, NULL);
yylval->distance.type = PW_PERCENT;
yylval->distance.style = DASH;
return T_PIXEL;
}
<PROPERTIES>#{HEX}{8} {
union { unsigned int val; struct { unsigned char b,g,r,a;};} val;
val.val = (unsigned int)strtoull ( &yytext[1], NULL, 16);
yylval->colorval.alpha = val.a/255.0;
yylval->colorval.red = val.r/255.0;
yylval->colorval.green = val.g/255.0;
yylval->colorval.blue = val.b/255.0;
return T_COLOR;
}
<PROPERTIES>argb:{HEX}{8} {
union { unsigned int val; struct { unsigned char b,g,r,a;};} val;
val.val = (unsigned int)strtoull ( &yytext[1], NULL, 16);
yylval->colorval.alpha = val.a/255.0;
yylval->colorval.red = val.r/255.0;
yylval->colorval.green = val.g/255.0;
yylval->colorval.blue = val.b/255.0;
return T_COLOR;
}
<PROPERTIES>#{HEX}{6} {
union { unsigned int val; struct { unsigned char b,g,r,a;};} val;
val.val = (unsigned int)g_ascii_strtoull ( &yytext[1], NULL, 16);
yylval->colorval.alpha = 1.0;
yylval->colorval.red = val.r/255.0;
yylval->colorval.green = val.g/255.0;
yylval->colorval.blue = val.b/255.0;
return T_COLOR;
}
<PROPERTIES>rgba\({NUMBER}{1,3},{NUMBER}{1,3},{NUMBER}{1,3},[01](\.{NUMBER}+)?\) {
char *endptr = &yytext[5];
yylval->colorval.red = g_ascii_strtoull ( endptr, &endptr, 10);
yylval->colorval.green= g_ascii_strtoull ( endptr+1, &endptr, 10);
yylval->colorval.blue= g_ascii_strtoull ( endptr+1, &endptr, 10);
yylval->colorval.alpha= g_ascii_strtod ( endptr+1, NULL);
return T_COLOR;
}
<PROPERTIES>rgb\({NUMBER}{1,3},{NUMBER}{1,3},{NUMBER}{1,3}\) {
char *endptr = &yytext[4];
yylval->colorval.red = g_ascii_strtoull ( endptr, &endptr, 10);
yylval->colorval.green = g_ascii_strtoull ( endptr+1, &endptr, 10);
yylval->colorval.blue = g_ascii_strtoull ( endptr+1, &endptr, 10);
yylval->colorval.alpha = 1.0;
return T_COLOR;
}
<PROPERTIES>{CENTER} {
yylval->ival = WL_CENTER;
return T_POSITION;
}
<PROPERTIES>{EAST} {
yylval->ival = WL_EAST;
return T_POSITION;
}
<PROPERTIES>{WEST} {
yylval->ival = WL_WEST;
return T_POSITION;
}
<PROPERTIES>{SOUTH}{EAST} {
yylval->ival = WL_SOUTH_EAST;
return T_POSITION;
}
<PROPERTIES>{SOUTH}{WEST} {
yylval->ival = WL_SOUTH_WEST;
return T_POSITION;
}
<PROPERTIES>{SOUTH} {
yylval->ival = WL_SOUTH;
return T_POSITION;
}
<PROPERTIES>{NORTH}{EAST} {
yylval->ival = WL_NORTH_EAST;
return T_POSITION;
}
<PROPERTIES>{NORTH}{WEST} {
yylval->ival = WL_NORTH_WEST;
return T_POSITION;
}
<PROPERTIES>{NORTH} {
yylval->ival = WL_NORTH;
return T_POSITION;
}
<PROPERTIES>NORTH {
yylval->ival = WL_NORTH;
return T_POSITION;
}
<INITIAL><<EOF>> {
g_queue_free ( queue );
// Reset pointer to NULL
queue = NULL;
yyterminate();
}
<*>\n {
yylloc->last_column = 1;
yylloc->last_line ++;
};
<*>(\r\n) {
yylloc->last_column = 1;
yylloc->last_line ++;
};
<INITIAL>. {
const char *error_msg = "Expected 'root' element or a 'named' element.\n"\
"Place all global properties in a root element:\n"\
" * {\n"\
" }\n";
YY_FATAL_ERROR( error_msg );
}
<*>. {
fprintf(stderr, "Invalid character: '%c'\n", *yytext);
yyterminate();
}
%%

185
lexer/theme-parser.y Normal file
View file

@ -0,0 +1,185 @@
%define api.pure
%glr-parser
%skeleton "glr.c"
%locations
%debug
%error-verbose
%code requires {
#include "theme.h"
}
%{
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "lexer/theme-parser.h"
ThemeWidget *rofi_theme = NULL;
void yyerror(YYLTYPE *yylloc, const char* s);
int yylex (YYSTYPE *, YYLTYPE *);
%}
%union {
int ival;
double fval;
char *sval;
int bval;
ThemeColor colorval;
ThemeWidget *theme;
GList *name_path;
Property *property;
GHashTable *property_list;
Distance distance;
}
%token <ival> T_INT
%token <fval> T_DOUBLE
%token <sval> T_STRING
%token <sval> N_STRING
%token <ival> T_POSITION;
%token <sval> NAME_ELEMENT "Element name"
%token <bval> T_BOOLEAN
%token <colorval> T_COLOR
%token <distance> T_PIXEL
%token <sval> T_LINK
%token <sval> FIRST_NAME
%token BOPEN "bracket open";
%token BCLOSE "bracket close";
%token PSEP "property separator";
%token PCLOSE "property close";
%token NSEP "Name separator";
%token NAME_PREFIX "Name prefix";
%token WHITESPACE "White space";
%token PDEFAULTS "Default settings";
%type <sval> entry
%type <sval> pvalue
%type <theme> entries
%type <name_path> name_path
%type <property> property
%type <property_list> property_list
%type <property_list> optional_properties
%start entries
%%
entries:
%empty {
// There is always a base widget.
if (rofi_theme == NULL ){
$$ = rofi_theme = (ThemeWidget*)g_malloc0 (sizeof(ThemeWidget));
rofi_theme->name = g_strdup ( "Root" );
}
}
| entries
entry {
}
;
entry:
NAME_PREFIX name_path BOPEN optional_properties BCLOSE
{
ThemeWidget *widget = rofi_theme;
for ( GList *iter = g_list_first ( $2 ); iter ; iter = g_list_next ( iter ) ) {
widget = rofi_theme_find_or_create_name ( widget, iter->data );
}
g_list_foreach ( $2, (GFunc)g_free , NULL );
g_list_free ( $2 );
widget->set = TRUE;
rofi_theme_widget_add_properties ( widget, $4);
}
|
PDEFAULTS BOPEN optional_properties BCLOSE {
rofi_theme_widget_add_properties ( rofi_theme, $3);
}
;
/**
* properties
*/
optional_properties
: %empty { $$ = NULL; }
| property_list { $$ = $1; }
;
property_list:
property {
$$ = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify)rofi_theme_property_free );
g_hash_table_replace ( $$, $1->name, $1 );
}
| property_list property {
// Old will be free'ed, and key/value will be replaced.
g_hash_table_replace ( $$, $2->name, $2 );
}
;
property
: pvalue PSEP T_INT PCLOSE {
$$ = rofi_theme_property_create ( P_INTEGER );
$$->name = $1;
$$->value.i = $3;
}
| pvalue PSEP T_DOUBLE PCLOSE {
$$ = rofi_theme_property_create ( P_DOUBLE );
$$->name = $1;
$$->value.f = $3;
}
| pvalue PSEP T_COLOR PCLOSE {
$$ = rofi_theme_property_create ( P_COLOR );
$$->name = $1;
$$->value.color = $3;
}
| pvalue PSEP T_STRING PCLOSE {
$$ = rofi_theme_property_create ( P_STRING );
$$->name = $1;
$$->value.s = $3;
}
| pvalue PSEP T_LINK PCLOSE {
$$ = rofi_theme_property_create ( P_LINK );
$$->name = $1;
$$->value.link.name = $3;
}
| pvalue PSEP T_BOOLEAN PCLOSE {
$$ = rofi_theme_property_create ( P_BOOLEAN );
$$->name = $1;
$$->value.b = $3;
}
| pvalue PSEP T_PIXEL PCLOSE {
$$ = rofi_theme_property_create ( P_PADDING );
$$->name = $1;
$$->value.padding = (Padding){ $3, $3, $3, $3 };
}
| pvalue PSEP T_PIXEL T_PIXEL PCLOSE {
$$ = rofi_theme_property_create ( P_PADDING );
$$->name = $1;
$$->value.padding = (Padding){ $3, $4, $3, $4 };
}
| pvalue PSEP T_PIXEL T_PIXEL T_PIXEL PCLOSE {
$$ = rofi_theme_property_create ( P_PADDING );
$$->name = $1;
$$->value.padding = (Padding){ $3, $4, $5, $4 };
}
| pvalue PSEP T_PIXEL T_PIXEL T_PIXEL T_PIXEL PCLOSE {
$$ = rofi_theme_property_create ( P_PADDING );
$$->name = $1;
$$->value.padding = (Padding){ $3, $4, $5, $6 };
}
| pvalue PSEP T_POSITION PCLOSE{
$$ = rofi_theme_property_create ( P_POSITION );
$$->name = $1;
$$->value.i = $3;
}
;
pvalue: N_STRING { $$ = $1; }
name_path:
NAME_ELEMENT { $$ = g_list_append ( NULL, $1 );}
| name_path NSEP NAME_ELEMENT { $$ = g_list_append ( $1, $3);}
| name_path NSEP { $$ = $1; }
;
%%

76
script/rofi-convert-theme.sh Executable file
View file

@ -0,0 +1,76 @@
#!/usr/bin/env bash
#
# This code is released in public domain by Dave Davenport <qball@gmpclient.org>
# This converts from old style theme (< 1.4) to new style theme (>= 1.4)
#
function update_color ()
{
var=${1}
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
if [[ ${var} =~ argb:[0-9a-fA-F]{6,8} ]]
then
echo "#${var:5}"
else
echo ${var}
fi
}
function parse_window_color ()
{
OLDIFS=${IFS}
IFS=","
entries=( ${1} )
echo "@window {"
echo " background: $( update_color ${entries[0]});"
echo " foreground: $( update_color ${entries[1]});"
echo "}"
if [ -n "${entries[2]}" ]
then
echo "@separator {"
echo " foreground: $( update_color ${entries[2]});"
echo "}"
echo "@scrollbar {"
echo " foreground: $( update_color ${entries[2]});"
echo "}"
fi
IFS=${OLDIFS}
}
function parse_color ()
{
state=$1
OLDIFS=${IFS}
IFS=","
entries=( ${2} )
echo "@textbox normal.${state} { "
echo " background: $( update_color ${entries[0]});"
echo " foreground: $( update_color ${entries[1]});"
echo "}"
echo "@textbox selected.${state} { "
echo " background: $( update_color ${entries[3]});"
echo " foreground: $( update_color ${entries[4]});"
echo "}"
echo "@textbox alternate.${state} { "
echo " background: $( update_color ${entries[2]});"
echo " foreground: $( update_color ${entries[1]});"
echo "}"
IFS=${OLDIFS}
}
while read LINE
do
if [[ ${LINE} =~ ^rofi\.color-normal: ]]
then
parse_color "normal" "${LINE:18}"
elif [[ ${LINE} =~ ^rofi\.color-urgent: ]]
then
parse_color "urgent" "${LINE:18}"
elif [[ ${LINE} =~ ^rofi\.color-active: ]]
then
parse_color "active" "${LINE:18}"
elif [[ ${LINE} =~ ^rofi\.color-window: ]]
then
parse_window_color "${LINE:18}"
fi
done

View file

@ -295,6 +295,27 @@ int find_arg_str ( const char * const key, char** val )
return FALSE; return FALSE;
} }
const char ** find_arg_strv ( const char *const key )
{
const char **retv =NULL;
int length = 0;
for ( int i = 0; i < stored_argc; i++ ) {
if ( strcasecmp ( stored_argv[i], key ) == 0 && i < (stored_argc -1 ) ){
length++;
}
}
if ( length > 0 ) {
retv = g_malloc0((length+1)*sizeof(char*));
int index = 0;
for ( int i = 0; i < stored_argc; i++ ) {
if ( strcasecmp ( stored_argv[i], key ) == 0 && i < (stored_argc -1 ) ){
retv[index++] = stored_argv[i+1];
}
}
}
return retv;
}
int find_arg_int ( const char * const key, int *val ) int find_arg_int ( const char * const key, int *val )
{ {
int i = find_arg ( key ); int i = find_arg ( key );

View file

@ -64,6 +64,8 @@
#include "gitconfig.h" #include "gitconfig.h"
#include "theme.h"
// Pidfile. // Pidfile.
char *pidfile = NULL; char *pidfile = NULL;
const char *cache_dir = NULL; const char *cache_dir = NULL;
@ -576,8 +578,9 @@ static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, xcb_connection_t
xcb_flush ( xdisplay ); xcb_flush ( xdisplay );
--error_trap_depth; --error_trap_depth;
} }
/** Retry count of grabbing keyboard. */
unsigned int lazy_grab_retry_count_kb = 0; unsigned int lazy_grab_retry_count_kb = 0;
/** Retry count of grabbing pointer. */
unsigned int lazy_grab_retry_count_pt = 0; unsigned int lazy_grab_retry_count_pt = 0;
static gboolean lazy_grab_pointer ( G_GNUC_UNUSED gpointer data ) static gboolean lazy_grab_pointer ( G_GNUC_UNUSED gpointer data )
{ {
@ -942,6 +945,31 @@ int main ( int argc, char *argv[] )
// Parse command line for settings, independent of other -no-config. // Parse command line for settings, independent of other -no-config.
config_parse_cmd_options_dynamic ( ); config_parse_cmd_options_dynamic ( );
if ( config.theme ) {
TICK_N ( "Parse theme" );
rofi_theme_parse_file ( config.theme );
TICK_N ( "Parsed theme" );
} else {
rofi_theme_convert_old_theme ( );
}
const char ** theme_str = find_arg_strv ( "-theme-str" );
if ( theme_str ) {
for ( int index = 0; theme_str && theme_str[index]; index++ ){
if ( ! rofi_theme_parse_string ( theme_str[index] ) ){
fprintf(stderr, "Failed to parse: %s\n", theme_str[index]);
exit ( EXIT_FAILURE );
}
}
g_free ( theme_str );
}
if ( find_arg ( "-dump-theme" ) >= 0 ){
rofi_theme_print ( rofi_theme );
exit (EXIT_SUCCESS);
}
// Dump. // Dump.
// catch help request // catch help request
if ( find_arg ( "-h" ) >= 0 || find_arg ( "-help" ) >= 0 || find_arg ( "--help" ) >= 0 ) { if ( find_arg ( "-h" ) >= 0 || find_arg ( "-help" ) >= 0 || find_arg ( "--help" ) >= 0 ) {

840
source/theme.c Normal file
View file

@ -0,0 +1,840 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "theme.h"
#include "lexer/theme-parser.h"
#include "helper.h"
#include "settings.h"
#include "widgets/textbox.h"
#include "view.h"
/** Logging domain for theme */
#define LOG_DOMAIN "Theme"
void yyerror ( YYLTYPE *ylloc, const char *);
static gboolean distance_compare ( Distance d, Distance e )
{
return ( d.type == e.type && d.distance == e.distance && d.style == e.style );
}
ThemeWidget *rofi_theme_find_or_create_name ( ThemeWidget *base, const char *name )
{
for ( unsigned int i = 0; i < base->num_widgets;i++){
if ( g_strcmp0(base->widgets[i]->name, name) == 0 ){
return base->widgets[i];
}
}
base->widgets = g_realloc ( base->widgets, sizeof(ThemeWidget*)*(base->num_widgets+1));
base->widgets[base->num_widgets] = g_malloc0(sizeof(ThemeWidget));
ThemeWidget *retv = base->widgets[base->num_widgets];
retv->parent = base;
retv->name = g_strdup(name);
base->num_widgets++;
return retv;
}
/**
* Properties
*/
Property *rofi_theme_property_create ( PropertyType type )
{
Property *retv = g_malloc0 ( sizeof(Property) );
retv->type = type;
return retv;
}
void rofi_theme_property_free ( Property *p )
{
if ( p == NULL ) {
return;
}
g_free ( p->name );
if ( p->type == P_STRING ) {
g_free ( p->value.s );
} else if ( p->type == P_LINK ) {
g_free ( p->value.link.name );
}
g_free(p);
}
void rofi_theme_free ( ThemeWidget *widget )
{
if ( widget == NULL ){
return;
}
if ( widget->properties ) {
g_hash_table_destroy ( widget->properties );
}
for ( unsigned int i = 0; i < widget->num_widgets; i++ ){
rofi_theme_free ( widget->widgets[i] );
}
g_free ( widget->widgets );
g_free ( widget->name );
g_free ( widget );
}
/**
* print
*/
static void rofi_theme_print_distance ( Distance d )
{
if ( d.type == PW_PX ) {
printf("%upx ", (int)d.distance );
} else if ( d.type == PW_PERCENT ) {
printf("%f%% ", d.distance );
} else {
printf("%fem ", d.distance );
}
if ( d.style == DASH ) {
printf("dash ");
}
}
/** Textual representation of Window Location */
const char const * WindowLocationStr[9] = {
"center",
"northwest",
"north",
"northeast",
"east",
"southeast",
"south",
"southwest",
"west"
};
static void rofi_theme_print_property_index ( size_t pnl, int depth, Property *p )
{
int pl = strlen ( p->name );
printf("%*s%s:%*s ", depth, "", p->name, (int)pnl-pl,"" );
switch ( p->type )
{
case P_POSITION:
printf("%s;", WindowLocationStr[p->value.i]);
break;
case P_STRING:
printf("\"%s\";", p->value.s);
break;
case P_INTEGER:
printf("%d;", p->value.i);
break;
case P_DOUBLE:
printf("%.2f;", p->value.f);
break;
case P_BOOLEAN:
printf("%s;", p->value.b?"true":"false");
break;
case P_COLOR:
printf("#%02X%02X%02X%02X;",
(unsigned char)(p->value.color.alpha*255.0),
(unsigned char)(p->value.color.red*255.0),
(unsigned char)(p->value.color.green*255.0),
(unsigned char)(p->value.color.blue*255.0));
break;
case P_PADDING:
if ( distance_compare ( p->value.padding.top, p->value.padding.bottom) &&
distance_compare ( p->value.padding.left, p->value.padding.right) &&
distance_compare ( p->value.padding.left, p->value.padding.top) ) {
rofi_theme_print_distance ( p->value.padding.left );
} else if ( distance_compare ( p->value.padding.top, p->value.padding.bottom) &&
distance_compare ( p->value.padding.left, p->value.padding.right)){
rofi_theme_print_distance ( p->value.padding.top );
rofi_theme_print_distance ( p->value.padding.left );
} else if ( !distance_compare ( p->value.padding.top, p->value.padding.bottom) &&
distance_compare ( p->value.padding.left, p->value.padding.right)){
rofi_theme_print_distance ( p->value.padding.top );
rofi_theme_print_distance ( p->value.padding.left );
rofi_theme_print_distance ( p->value.padding.bottom);
} else {
rofi_theme_print_distance ( p->value.padding.top );
rofi_theme_print_distance ( p->value.padding.right );
rofi_theme_print_distance ( p->value.padding.bottom);
rofi_theme_print_distance ( p->value.padding.left );
}
printf(";");
break;
case P_LINK:
printf("%s;", p->value.link.name);
break;
}
putchar ( '\n' );
}
static void rofi_theme_print_index ( ThemeWidget *widget )
{
GHashTableIter iter;
gpointer key, value;
if ( widget->properties ){
int index = 0;
GList *list = NULL;
ThemeWidget *w = widget;
while ( w){
if ( g_strcmp0(w->name,"Root") == 0 ) {
break;
}
list = g_list_prepend ( list, w->name );
w = w->parent;
}
if ( g_list_length ( list ) > 0 ) {
index = 4;
for ( GList *iter = g_list_first ( list ); iter != NULL; iter = g_list_next ( iter ) ) {
char *name = (char *)iter->data;
if ( iter->prev == NULL ){
putchar ( '#' );
}
fputs(name, stdout);
if ( iter->next ) {
putchar('.');
}
}
printf(" {\n");
} else {
index = 4;
printf("* {\n");
}
size_t property_name_length = 0;
g_hash_table_iter_init (&iter, widget->properties);
while (g_hash_table_iter_next (&iter, &key, &value))
{
Property *p = (Property*)value;
property_name_length = MAX ( strlen (p->name), property_name_length );
}
g_hash_table_iter_init (&iter, widget->properties);
while (g_hash_table_iter_next (&iter, &key, &value))
{
Property *p = (Property*)value;
rofi_theme_print_property_index ( property_name_length, index, p );
}
printf("}\n");
g_list_free ( list );
}
for ( unsigned int i = 0; i < widget->num_widgets;i++){
rofi_theme_print_index ( widget->widgets[i] );
}
}
void rofi_theme_print ( ThemeWidget *widget )
{
rofi_theme_print_index ( widget );
}
/**
* Main lex parser.
*/
int yyparse();
/**
* Destroy the internal of lex parser.
*/
void yylex_destroy( void );
/**
* Global handle input file to flex parser.
*/
extern FILE* yyin;
/**
* @param yylloc The file location.
* @param s Error message string.
*
* Error handler for the lex parser.
*/
void yyerror(YYLTYPE *yylloc, const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
fprintf(stderr, "From line %d column %d to line %d column %d\n", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column);
exit(EXIT_FAILURE);
}
static gboolean rofi_theme_steal_property_int ( gpointer key, gpointer value, gpointer user_data)
{
GHashTable *table = (GHashTable*)user_data;
g_hash_table_replace ( table, key, value);
return TRUE;
}
void rofi_theme_widget_add_properties ( ThemeWidget *widget, GHashTable *table )
{
if ( table == NULL ) {
return;
}
if ( widget->properties == NULL ){
widget->properties = table;
return;
}
g_hash_table_foreach_steal ( table, rofi_theme_steal_property_int, widget->properties );
g_hash_table_destroy ( table );
}
/**
* Public API
*/
static ThemeWidget *rofi_theme_find_single ( ThemeWidget *widget, const char *name)
{
for ( unsigned int j = 0; j < widget->num_widgets;j++){
if ( g_strcmp0(widget->widgets[j]->name, name ) == 0 ){
return widget->widgets[j];
}
}
return widget;
}
static ThemeWidget *rofi_theme_find ( ThemeWidget *widget , const char *name, const gboolean exact )
{
if ( widget == NULL || name == NULL ) {
return widget;
}
char **names = g_strsplit ( name, "." , 0 );
int found = TRUE;
for ( unsigned int i = 0; found && names && names[i]; i++ ){
found = FALSE;
ThemeWidget *f = rofi_theme_find_single ( widget, names[i]);
if ( f != widget ){
widget = f;
found = TRUE;
}
}
g_strfreev(names);
if ( !exact || found ){
return widget;
} else {
return NULL;
}
}
static void rofi_theme_resolve_link_property ( Property *p, int depth )
{
// Set name, remove '@' prefix.
const char *name = p->value.link.name +1;
if ( depth > 20 ){
g_log ( LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Found more then 20 redirects for property. Stopping.");
p->value.link.ref = p;
return;
}
if( g_hash_table_contains ( rofi_theme->properties, name ) ) {
Property *pr = g_hash_table_lookup ( rofi_theme->properties, name );
if ( pr->type == P_LINK ) {
if ( pr->value.link.ref == NULL ) {
rofi_theme_resolve_link_property ( pr, depth+1);
}
if ( pr->value.link.ref != pr ){
p->value.link.ref = pr->value.link.ref;
return;
}
} else {
p->value.link.ref = pr;
return;
}
}
// No found, set ref to self.
p->value.link.ref = p;
}
static Property *rofi_theme_find_property ( ThemeWidget *widget, PropertyType type, const char *property, gboolean exact )
{
while ( widget ) {
if ( widget->properties && g_hash_table_contains ( widget->properties, property) ) {
Property *p = g_hash_table_lookup ( widget->properties, property);
if ( p->type == P_LINK ) {
if ( p->value.link.ref == NULL ) {
// Resolve link.
rofi_theme_resolve_link_property ( p, 0 );
}
if ( p->value.link.ref->type == type ){
return p->value.link.ref;
}
}
if ( p->type == type ){
return p;
}
// Padding and integer can be converted.
if ( p->type == P_INTEGER && type == P_PADDING ){
return p;
}
}
if ( exact ) {
return NULL;
}
widget = widget->parent;
}
return NULL;
}
static ThemeWidget *rofi_theme_find_widget ( const char *name, const char *state, gboolean exact )
{
// First find exact match based on name.
ThemeWidget *widget = rofi_theme_find ( rofi_theme, name, exact );
widget = rofi_theme_find ( widget, state, exact );
return widget;
}
int rofi_theme_get_position ( const widget *widget, const char *property, int def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_POSITION, property, FALSE );
if ( p ){
return p->value.i;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
int rofi_theme_get_integer ( const widget *widget, const char *property, int def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_INTEGER, property, FALSE );
if ( p ){
return p->value.i;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
int rofi_theme_get_integer_exact ( const widget *widget, const char *property, int def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, TRUE );
Property *p = rofi_theme_find_property ( wid, P_INTEGER, property, TRUE );
if ( p ){
return p->value.i;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
Distance rofi_theme_get_distance ( const widget *widget, const char *property, int def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_PADDING, property, FALSE );
if ( p ){
if ( p->type == P_INTEGER ){
return (Distance){p->value.i,PW_PX, SOLID};
} else {
return p->value.padding.left;
}
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return (Distance){def, PW_PX, SOLID};
}
int rofi_theme_get_boolean ( const widget *widget, const char *property, int def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_BOOLEAN, property, FALSE );
if ( p ){
return p->value.b;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
char *rofi_theme_get_string ( const widget *widget, const char *property, char *def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_STRING, property, FALSE );
if ( p ){
return p->value.s;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
double rofi_theme_get_double ( const widget *widget, const char *property, double def )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_DOUBLE, property, FALSE );
if ( p ){
return p->value.b;
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return def;
}
void rofi_theme_get_color ( const widget *widget, const char *property, cairo_t *d)
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_COLOR, property, FALSE );
if ( p ){
cairo_set_source_rgba ( d,
p->value.color.red,
p->value.color.green,
p->value.color.blue,
p->value.color.alpha
);
} else {
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
}
}
Padding rofi_theme_get_padding ( const widget *widget, const char *property, Padding pad )
{
ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE );
Property *p = rofi_theme_find_property ( wid, P_PADDING, property, FALSE );
if ( p ){
if ( p->type == P_PADDING ){
pad = p->value.padding;
} else {
Distance d = (Distance){p->value.i, PW_PX, SOLID};
return (Padding){d,d,d,d};
}
}
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Theme entry: #%s %s property %s unset.", widget->name, widget->state?widget->state:"", property );
return pad;
}
int distance_get_pixel ( Distance d, Orientation ori )
{
if ( d.type == PW_EM ){
return d.distance*textbox_get_estimated_char_height();
} else if ( d.type == PW_PERCENT ) {
if ( ori == ORIENTATION_VERTICAL ){
int height = 0;
rofi_view_get_current_monitor ( NULL, &height );
return (d.distance*height)/(100.0);
} else {
int width = 0;
rofi_view_get_current_monitor ( &width, NULL );
return (d.distance*width)/(100.0);
}
}
return d.distance;
}
void distance_get_linestyle ( Distance d, cairo_t *draw )
{
if ( d.style == DASH ){
const double dashes[1] = { 4 };
cairo_set_dash ( draw, dashes, 1, 0.0 );
} else {
cairo_set_dash ( draw, NULL, 0, 0.0);
}
}
#ifdef THEME_CONVERTER
static Property* rofi_theme_convert_get_color ( const char *color, const char *name )
{
Color c = color_get ( color );
Property *p = rofi_theme_property_create ( P_COLOR );
p->name = g_strdup(name);
p->value.color.alpha = c.alpha;
p->value.color.red = c.red;
p->value.color.green = c.green;
p->value.color.blue = c.blue;
return p;
}
static void rofi_theme_convert_create_property_ht ( ThemeWidget *widget )
{
if ( widget->properties == NULL ) {
widget->properties = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, (GDestroyNotify)rofi_theme_property_free );
}
}
void rofi_theme_convert_old_theme ( void )
{
if ( rofi_theme != NULL ){
return;
}
rofi_theme = (ThemeWidget*)g_malloc0 ( sizeof ( ThemeWidget ) );
rofi_theme->name = g_strdup ( "Root" );
rofi_theme_convert_create_property_ht ( rofi_theme );
ThemeWidget *window_widget = rofi_theme_find_or_create_name ( rofi_theme , "window" );
rofi_theme_convert_create_property_ht ( window_widget );
ThemeWidget *mainbox_widget = rofi_theme_find_or_create_name ( window_widget, "mainbox" );
rofi_theme_convert_create_property_ht ( mainbox_widget );
ThemeWidget *message = rofi_theme_find_or_create_name ( mainbox_widget, "message" );
ThemeWidget *message_box = rofi_theme_find_or_create_name ( message, "box" );
rofi_theme_convert_create_property_ht ( message_box );
ThemeWidget *listview_widget = rofi_theme_find_or_create_name ( mainbox_widget, "listview" );
rofi_theme_convert_create_property_ht ( listview_widget );
ThemeWidget *sidebar_widget = rofi_theme_find_or_create_name ( mainbox_widget, "sidebar" );
ThemeWidget *sidebarbox_widget = rofi_theme_find_or_create_name ( sidebar_widget, "box" );
rofi_theme_convert_create_property_ht ( sidebarbox_widget );
{
Property *p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("border");
p->value.i = 0;
g_hash_table_replace ( mainbox_widget->properties, p->name, p);
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("padding");
p->value.i = config.padding;
g_hash_table_replace ( window_widget->properties, p->name, p);
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("padding");
p->value.i = 0;
g_hash_table_replace ( mainbox_widget->properties, p->name, p);
// Spacing
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("spacing");
p->value.i = config.line_margin;
g_hash_table_replace ( rofi_theme->properties, p->name, p );
}
{
// Background
Property *p = rofi_theme_property_create ( P_COLOR );
p->name = g_strdup("background");
p->value.color.alpha = 0;
p->value.color.red = 0;
p->value.color.green= 0;
p->value.color.blue= 0;
g_hash_table_replace ( rofi_theme->properties, p->name, p );
ThemeWidget *inputbar_widget = rofi_theme_find_or_create_name ( mainbox_widget, "inputbar" );
rofi_theme_convert_create_property_ht ( inputbar_widget );
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("spacing");
p->value.i = 0;
g_hash_table_replace ( inputbar_widget->properties, p->name, p );
LineStyle style = (g_strcmp0(config.separator_style,"dash") == 0)?DASH:SOLID;
int place_end = ( config.location == WL_SOUTH_EAST || config.location == WL_SOUTH || config.location == WL_SOUTH_WEST );
p = rofi_theme_property_create ( P_PADDING );
p->name = g_strdup("border");
Distance d = (Distance){config.menu_bw, PW_PX, style};
if ( place_end ){
p->value.padding.bottom= d;
} else {
p->value.padding.top= d;
}
g_hash_table_replace ( listview_widget->properties, p->name, p );
p = rofi_theme_property_create ( P_PADDING );
p->name = g_strdup("border");
d = (Distance){config.menu_bw, PW_PX, style};
if ( place_end ){
p->value.padding.bottom= d;
} else {
p->value.padding.top= d;
}
g_hash_table_replace ( message_box->properties, p->name, p );
/**
* Sidebar top
*/
p = rofi_theme_property_create ( P_PADDING );
p->name = g_strdup("border");
d = (Distance){config.menu_bw, PW_PX, style};
p->value.padding.top= d;
g_hash_table_replace ( sidebarbox_widget->properties, p->name, p );
p = rofi_theme_property_create ( P_PADDING );
p->name = g_strdup("padding");
d = (Distance){config.line_margin, PW_PX, SOLID};
if ( place_end ){
p->value.padding.bottom= d;
} else {
p->value.padding.top= d;
}
g_hash_table_replace ( listview_widget->properties, p->name, p );
p = rofi_theme_property_create ( P_PADDING );
p->name = g_strdup("padding");
d = (Distance){config.line_margin, PW_PX, SOLID};
if ( place_end ){
p->value.padding.bottom= d;
} else {
p->value.padding.top= d;
}
g_hash_table_replace ( message_box->properties, p->name, p );
}
{
Property *p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("columns");
p->value.i = config.menu_columns;
g_hash_table_replace ( listview_widget->properties, p->name, p );
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("fixed-height");
p->value.i = !(config.fixed_num_lines);
g_hash_table_replace ( listview_widget->properties, p->name, p );
}
{
// Border width.
rofi_theme_convert_create_property_ht ( window_widget );
// Padding
Property *p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("padding");
p->value.i = config.padding;
g_hash_table_replace ( window_widget->properties, p->name, p );
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup("border");
p->value.i = config.menu_bw;
g_hash_table_replace ( window_widget->properties, p->name, p );
}
{
gchar **vals = g_strsplit ( config.color_window, ",", 3 );
if ( vals != NULL ){
if ( vals[0] != NULL ) {
Property *p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( window_widget->properties, p->name, p );
if ( vals[1] != NULL ) {
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( window_widget->properties, p->name, p );
ThemeWidget *inputbar = rofi_theme_find_or_create_name ( mainbox_widget, "inputbar" );
ThemeWidget *widget = rofi_theme_find_or_create_name ( inputbar, "box" );
rofi_theme_convert_create_property_ht ( widget );
if ( vals[2] != NULL ) {
p = rofi_theme_convert_get_color ( vals[2], "foreground" );
g_hash_table_replace ( window_widget->properties, p->name, p );
} else {
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( window_widget->properties, p->name, p );
}
}
}
}
g_strfreev ( vals );
{
Property *p = NULL;
ThemeWidget *widget = rofi_theme_find_or_create_name ( listview_widget, "element" );
ThemeWidget *scrollbar = rofi_theme_find_or_create_name ( listview_widget, "scrollbar" );
ThemeWidget *wnormal = rofi_theme_find_or_create_name ( widget, "normal" );
ThemeWidget *wselected = rofi_theme_find_or_create_name ( widget, "selected" );
ThemeWidget *walternate = rofi_theme_find_or_create_name ( widget, "alternate" );
rofi_theme_convert_create_property_ht ( widget );
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("border");
p->value.i = 0;
g_hash_table_replace ( widget->properties, p->name, p);
rofi_theme_convert_create_property_ht ( scrollbar );
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("border");
p->value.i = 0;
g_hash_table_replace ( scrollbar->properties, p->name, p);
p = rofi_theme_property_create ( P_INTEGER );
p->name = g_strdup ("padding");
p->value.i = 0;
g_hash_table_replace ( scrollbar->properties, p->name, p);
gchar **vals = g_strsplit ( config.color_normal, ",", 5 );
if ( g_strv_length (vals) == 5 ) {
ThemeWidget *wnn = rofi_theme_find_or_create_name ( wnormal, "normal" );
rofi_theme_convert_create_property_ht ( wnn );
p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( wnn->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wnn->properties, p->name, p );
ThemeWidget *wsl = rofi_theme_find_or_create_name ( wselected, "normal" );
rofi_theme_convert_create_property_ht ( wsl );
p = rofi_theme_convert_get_color ( vals[3], "background" );
g_hash_table_replace ( wsl->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[4], "foreground" );
g_hash_table_replace ( wsl->properties, p->name, p );
ThemeWidget *wal = rofi_theme_find_or_create_name ( walternate, "normal" );
rofi_theme_convert_create_property_ht ( wal );
p = rofi_theme_convert_get_color ( vals[2], "background" );
g_hash_table_replace ( wal->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wal->properties, p->name, p );
ThemeWidget *inputbar = rofi_theme_find_or_create_name ( mainbox_widget, "inputbar" );
wnn = rofi_theme_find_or_create_name ( inputbar, "normal" );
rofi_theme_convert_create_property_ht ( wnn );
p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( wnn->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wnn->properties, p->name, p );
wnn = rofi_theme_find_or_create_name ( message, "normal" );
rofi_theme_convert_create_property_ht ( wnn );
p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( wnn->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wnn->properties, p->name, p );
}
g_strfreev ( vals );
vals = g_strsplit ( config.color_urgent, ",", 5 );
if ( g_strv_length (vals) == 5 ) {
ThemeWidget *wnn = rofi_theme_find_or_create_name ( wnormal, "urgent" );
rofi_theme_convert_create_property_ht ( wnn );
p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( wnn->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wnn->properties, p->name, p );
ThemeWidget *wsl = rofi_theme_find_or_create_name ( wselected, "urgent" );
rofi_theme_convert_create_property_ht ( wsl );
p = rofi_theme_convert_get_color ( vals[3], "background" );
g_hash_table_replace ( wsl->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[4], "foreground" );
g_hash_table_replace ( wsl->properties, p->name, p );
ThemeWidget *wal = rofi_theme_find_or_create_name ( walternate, "urgent" );
rofi_theme_convert_create_property_ht ( wal );
p = rofi_theme_convert_get_color ( vals[2], "background" );
g_hash_table_replace ( wal->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wal->properties, p->name, p );
}
g_strfreev ( vals );
vals = g_strsplit ( config.color_active, ",", 5 );
if ( g_strv_length (vals) == 5 ) {
ThemeWidget *wnn = rofi_theme_find_or_create_name ( wnormal, "active" );
rofi_theme_convert_create_property_ht ( wnn );
p = rofi_theme_convert_get_color ( vals[0], "background" );
g_hash_table_replace ( wnn->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wnn->properties, p->name, p );
ThemeWidget *wsl = rofi_theme_find_or_create_name ( wselected, "active" );
rofi_theme_convert_create_property_ht ( wsl );
p = rofi_theme_convert_get_color ( vals[3], "background" );
g_hash_table_replace ( wsl->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[4], "foreground" );
g_hash_table_replace ( wsl->properties, p->name, p );
ThemeWidget *wal = rofi_theme_find_or_create_name ( walternate, "active" );
rofi_theme_convert_create_property_ht ( wal );
p = rofi_theme_convert_get_color ( vals[2], "background" );
g_hash_table_replace ( wal->properties, p->name, p );
p = rofi_theme_convert_get_color ( vals[1], "foreground" );
g_hash_table_replace ( wal->properties, p->name, p );
}
g_strfreev ( vals );
}
}
}
gboolean rofi_theme_parse_file ( const char *file )
{
char *filename = rofi_expand_path ( file );
yyin = fopen ( filename, "rb");
if ( yyin == NULL ){
fprintf(stderr, "Failed to open file: %s: '%s'\n", filename, strerror ( errno ) );
g_free(filename);
return TRUE;
}
extern int str_len;
extern const char*input_str;
str_len = 0;
input_str = NULL;
while ( yyparse() );
yylex_destroy();
g_free(filename);
yyin = NULL;
return FALSE;
}
gboolean rofi_theme_parse_string ( const char *string )
{
extern int str_len;
extern const char*input_str;
yyin = NULL;
input_str = string;
str_len = strlen ( string );
while ( yyparse () );
yylex_destroy();
return TRUE;
}
#endif

View file

@ -58,10 +58,19 @@
#include "view.h" #include "view.h"
#include "view-internal.h" #include "view-internal.h"
#include "theme.h"
/** The Rofi View log domain */ /** The Rofi View log domain */
#define LOG_DOMAIN "View" #define LOG_DOMAIN "View"
#include "xcb.h" #include "xcb.h"
/**
* @param state The handle to the view
* @param qr Indicate if queue_redraw should be called on changes.
*
* Update the state of the view. This involves filter state.
*/
void rofi_view_update ( RofiViewState *state, gboolean qr );
static int rofi_view_calculate_height ( RofiViewState *state ); static int rofi_view_calculate_height ( RofiViewState *state );
@ -99,9 +108,11 @@ struct
/** timeout for reloading */ /** timeout for reloading */
guint idle_timeout; guint idle_timeout;
/** debug counter for redraws */ /** debug counter for redraws */
uint64_t count; unsigned long long count;
/** redraw idle time. */ /** redraw idle time. */
guint repaint_source; guint repaint_source;
/** Window fullscreen */
gboolean fullscreen;
} CacheState = { } CacheState = {
.main_window = XCB_WINDOW_NONE, .main_window = XCB_WINDOW_NONE,
.fake_bg = NULL, .fake_bg = NULL,
@ -113,8 +124,18 @@ struct
.idle_timeout = 0, .idle_timeout = 0,
.count = 0L, .count = 0L,
.repaint_source = 0, .repaint_source = 0,
.fullscreen = FALSE,
}; };
void rofi_view_get_current_monitor ( int *width, int *height)
{
if (width ){
*width = CacheState.mon.w;
}
if (height){
*height = CacheState.mon.h;
}
}
static char * get_matching_state ( void ) static char * get_matching_state ( void )
{ {
if ( config.case_sensitive ) { if ( config.case_sensitive ) {
@ -200,6 +221,10 @@ static void menu_capture_screenshot ( void )
static gboolean rofi_view_repaint ( G_GNUC_UNUSED void * data ) static gboolean rofi_view_repaint ( G_GNUC_UNUSED void * data )
{ {
if ( current_active_menu ) { if ( current_active_menu ) {
// Repaint the view (if needed).
// After a resize the edit_pixmap surface might not contain anything anymore.
// If we already re-painted, this does nothing.
rofi_view_update (current_active_menu, FALSE);
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "expose event" ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "expose event" );
TICK_N ( "Expose" ); TICK_N ( "Expose" );
xcb_copy_area ( xcb->connection, CacheState.edit_pixmap, CacheState.main_window, CacheState.gc, xcb_copy_area ( xcb->connection, CacheState.edit_pixmap, CacheState.main_window, CacheState.gc,
@ -231,22 +256,29 @@ static void rofi_view_update_prompt ( RofiViewState *state )
*/ */
static void rofi_view_calculate_window_position ( RofiViewState *state ) static void rofi_view_calculate_window_position ( RofiViewState *state )
{ {
if ( config.fullscreen ) { int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location );
int anchor = location;
if ( !listview_get_fixed_num_lines ( state->list_view ) ) {
anchor = location;
if ( location == WL_CENTER ) {
anchor = WL_NORTH;
} else if ( location == WL_EAST ) {
anchor = WL_NORTH_EAST;
} else if (location == WL_WEST ) {
anchor = WL_NORTH_WEST;
}
}
anchor = rofi_theme_get_position ( WIDGET ( state->main_window ), "anchor", anchor );
if ( CacheState.fullscreen ) {
state->x = CacheState.mon.x; state->x = CacheState.mon.x;
state->y = CacheState.mon.y; state->y = CacheState.mon.y;
return; return;
} }
state->y = CacheState.mon.y + ( CacheState.mon.h ) / 2;
if ( !config.fixed_num_lines && ( config.location == WL_CENTER || config.location == WL_EAST || config.location == WL_WEST ) ) { state->x = CacheState.mon.x + ( CacheState.mon.w ) / 2;
state->y = CacheState.mon.y + CacheState.mon.h / 2 - widget_get_height ( WIDGET ( state->input_bar ) );
}
else {
// Default location is center.
state->y = CacheState.mon.y + ( CacheState.mon.h - state->height ) / 2;
}
state->x = CacheState.mon.x + ( CacheState.mon.w - state->width ) / 2;
// Determine window location // Determine window location
switch ( config.location ) switch ( location )
{ {
case WL_NORTH_WEST: case WL_NORTH_WEST:
state->x = CacheState.mon.x; state->x = CacheState.mon.x;
@ -256,15 +288,15 @@ static void rofi_view_calculate_window_position ( RofiViewState *state )
case WL_NORTH_EAST: case WL_NORTH_EAST:
state->y = CacheState.mon.y; state->y = CacheState.mon.y;
case WL_EAST: case WL_EAST:
state->x = CacheState.mon.x + CacheState.mon.w - state->width; state->x = CacheState.mon.x + CacheState.mon.w;
break; break;
case WL_EAST_SOUTH: case WL_SOUTH_EAST:
state->x = CacheState.mon.x + CacheState.mon.w - state->width; state->x = CacheState.mon.x + CacheState.mon.w;
case WL_SOUTH: case WL_SOUTH:
state->y = CacheState.mon.y + CacheState.mon.h - state->height; state->y = CacheState.mon.y + CacheState.mon.h;
break; break;
case WL_SOUTH_WEST: case WL_SOUTH_WEST:
state->y = CacheState.mon.y + CacheState.mon.h - state->height; state->y = CacheState.mon.y + CacheState.mon.h;
case WL_WEST: case WL_WEST:
state->x = CacheState.mon.x; state->x = CacheState.mon.x;
break; break;
@ -272,6 +304,41 @@ static void rofi_view_calculate_window_position ( RofiViewState *state )
default: default:
break; break;
} }
switch ( anchor )
{
case WL_SOUTH_WEST:
state->y -= state->height;
break;
case WL_SOUTH:
state->x -= state->width/2;
state->y -= state->height;
break;
case WL_SOUTH_EAST:
state->x -= state->width;
state->y -= state->height;
break;
case WL_NORTH_EAST:
state->x -= state->width;
break;
case WL_NORTH_WEST:
break;
case WL_NORTH:
state->x -= state->width/2;
break;
case WL_EAST:
state->x -= state->width;
state->y -= state->height/2;
break;
case WL_WEST:
state->y -= state->height/2;
break;
case WL_CENTER:
state->y -= state->height/2;
state->x -= state->width/2;
break;
default:
break;
}
// Apply offset. // Apply offset.
state->x += config.x_offset; state->x += config.x_offset;
state->y += config.y_offset; state->y += config.y_offset;
@ -294,7 +361,10 @@ static void rofi_view_window_update_size ( RofiViewState * state )
CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height ); CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height );
CacheState.edit_draw = cairo_create ( CacheState.edit_surf ); CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
widget_resize ( WIDGET ( state->main_box ), state->width - 2 * state->border, state->height - 2 * state->border );
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Re-size window based internal request: %dx%d.", state->width, state->height );
// Should wrap main window in a widget.
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
} }
static gboolean rofi_view_reload_idle ( G_GNUC_UNUSED gpointer data ) static gboolean rofi_view_reload_idle ( G_GNUC_UNUSED gpointer data )
@ -319,7 +389,7 @@ void rofi_view_queue_redraw ( void )
{ {
if ( current_active_menu && CacheState.repaint_source == 0 ) { if ( current_active_menu && CacheState.repaint_source == 0 ) {
CacheState.count++; CacheState.count++;
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "redraw %lu", CacheState.count ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "redraw %llu", CacheState.count );
CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL ); CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL );
} }
} }
@ -382,7 +452,7 @@ void rofi_view_free ( RofiViewState *state )
} }
// Do this here? // Do this here?
// Wait for final release? // Wait for final release?
widget_free ( WIDGET ( state->main_box ) ); widget_free ( WIDGET ( state->main_window ) );
widget_free ( WIDGET ( state->overlay ) ); widget_free ( WIDGET ( state->overlay ) );
g_free ( state->line_map ); g_free ( state->line_map );
@ -489,23 +559,26 @@ static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data
} }
} }
static void rofi_view_setup_fake_transparency ( void ) static void rofi_view_setup_fake_transparency ( const char const *fake_background )
{ {
if ( CacheState.fake_bg == NULL ) { if ( CacheState.fake_bg == NULL ) {
cairo_surface_t *s = NULL; cairo_surface_t *s = NULL;
/** /**
* Select Background to use for fake transparency. * Select Background to use for fake transparency.
* Current options: 'screenshot','background' * Current options: 'real', 'screenshot','background'
*/ */
TICK_N ( "Fake start" ); TICK_N ( "Fake start" );
if ( g_strcmp0 ( config.fake_background, "screenshot" ) == 0 ) { if ( g_strcmp0 ( fake_background, "real" ) == 0 ){
return;
}
else if ( g_strcmp0 ( fake_background, "screenshot" ) == 0 ) {
s = x11_helper_get_screenshot_surface (); s = x11_helper_get_screenshot_surface ();
} }
else if ( g_strcmp0 ( config.fake_background, "background" ) == 0 ) { else if ( g_strcmp0 ( fake_background, "background" ) == 0 ) {
s = x11_helper_get_bg_surface (); s = x11_helper_get_bg_surface ();
} }
else { else {
char *fpath = rofi_expand_path ( config.fake_background ); char *fpath = rofi_expand_path ( fake_background );
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Opening %s to use as background.", fpath ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Opening %s to use as background.", fpath );
s = cairo_image_surface_create_from_png ( fpath ); s = cairo_image_surface_create_from_png ( fpath );
CacheState.fake_bgrel = TRUE; CacheState.fake_bgrel = TRUE;
@ -584,8 +657,11 @@ void __create_window ( MenuFlags menu_flags )
pango_cairo_font_map_set_resolution ( (PangoCairoFontMap *) font_map, (double) config.dpi ); pango_cairo_font_map_set_resolution ( (PangoCairoFontMap *) font_map, (double) config.dpi );
} }
// Setup font. // Setup font.
if ( config.menu_font ) { // Dummy widget.
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font ); container *win = container_create ( "window" );
char *font = rofi_theme_get_string ( WIDGET ( win ), "font" , config.menu_font );
if ( font ) {
PangoFontDescription *pfd = pango_font_description_from_string ( font );
pango_context_set_font_description ( p, pfd ); pango_context_set_font_description ( p, pfd );
pango_font_description_free ( pfd ); pango_font_description_free ( pfd );
} }
@ -605,7 +681,9 @@ void __create_window ( MenuFlags menu_flags )
window_set_atom_prop ( box, xcb->ewmh._NET_WM_WINDOW_TYPE, &( xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL ), 1 ); window_set_atom_prop ( box, xcb->ewmh._NET_WM_WINDOW_TYPE, &( xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL ), 1 );
x11_disable_decoration ( box ); x11_disable_decoration ( box );
} }
if ( config.fullscreen ) {
CacheState.fullscreen = rofi_theme_get_boolean ( WIDGET (win ), "fullscreen", config.fullscreen );
if ( CacheState.fullscreen ) {
xcb_atom_t atoms[] = { xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_FULLSCREEN, xcb->ewmh._NET_WM_STATE_FULLSCREEN,
xcb->ewmh._NET_WM_STATE_ABOVE xcb->ewmh._NET_WM_STATE_ABOVE
@ -620,12 +698,18 @@ void __create_window ( MenuFlags menu_flags )
CacheState.main_window = box; CacheState.main_window = box;
CacheState.flags = menu_flags; CacheState.flags = menu_flags;
monitor_active ( &( CacheState.mon ) ); monitor_active ( &( CacheState.mon ) );
if ( config.fake_transparency ) {
rofi_view_setup_fake_transparency (); char *transparency = rofi_theme_get_string ( WIDGET ( win ), "transparency", NULL);
if ( transparency == NULL && config.fake_transparency ){
transparency = config.fake_background;
}
if ( transparency ) {
rofi_view_setup_fake_transparency ( transparency );
} }
if ( xcb->sncontext != NULL ) { if ( xcb->sncontext != NULL ) {
sn_launchee_context_setup_window ( xcb->sncontext, CacheState.main_window ); sn_launchee_context_setup_window ( xcb->sncontext, CacheState.main_window );
} }
widget_free ( WIDGET ( win ) );
} }
/** /**
@ -633,20 +717,24 @@ void __create_window ( MenuFlags menu_flags )
* *
* Calculate the width of the window and the width of an element. * Calculate the width of the window and the width of an element.
*/ */
static void rofi_view_calculate_window_and_element_width ( RofiViewState *state ) static void rofi_view_calculate_window_width ( RofiViewState *state )
{ {
if ( config.fullscreen ) { if ( CacheState.fullscreen ) {
state->width = CacheState.mon.w; state->width = CacheState.mon.w;
return;
} }
else if ( config.menu_width < 0 ) { if ( config.menu_width < 0 ) {
double fw = textbox_get_estimated_char_width ( ); double fw = textbox_get_estimated_char_width ( );
state->width = -( fw * config.menu_width ); state->width = -( fw * config.menu_width );
state->width += 2 * state->border; state->width += widget_padding_get_padding_width ( WIDGET ( state->main_window ) );
} }
else{ else{
// Calculate as float to stop silly, big rounding down errors. // Calculate as float to stop silly, big rounding down errors.
state->width = config.menu_width < 101 ? ( CacheState.mon.w / 100.0f ) * ( float ) config.menu_width : config.menu_width; state->width = config.menu_width < 101 ? ( CacheState.mon.w / 100.0f ) * ( float ) config.menu_width : config.menu_width;
} }
// Use theme configured width, if set.
Distance width = rofi_theme_get_distance ( WIDGET ( state->main_window ), "width", state->width );
state->width = distance_get_pixel ( width, ORIENTATION_HORIZONTAL );
} }
/** /**
@ -758,15 +846,16 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB
} }
} }
void rofi_view_update ( RofiViewState *state ) void rofi_view_update ( RofiViewState *state, gboolean qr )
{ {
if ( !widget_need_redraw ( WIDGET ( state->main_box ) ) && !widget_need_redraw ( WIDGET ( state->overlay ) ) ) { if ( !widget_need_redraw ( WIDGET ( state->main_window ) ) && !widget_need_redraw ( WIDGET ( state->overlay ) ) ) {
return; return;
} }
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Redraw view" );
TICK (); TICK ();
cairo_t *d = CacheState.edit_draw; cairo_t *d = CacheState.edit_draw;
cairo_set_operator ( d, CAIRO_OPERATOR_SOURCE ); cairo_set_operator ( d, CAIRO_OPERATOR_SOURCE );
if ( config.fake_transparency && CacheState.fake_bg != NULL ) { if ( CacheState.fake_bg != NULL ) {
if ( CacheState.fake_bgrel ) { if ( CacheState.fake_bgrel ) {
cairo_set_source_surface ( d, CacheState.fake_bg, 0.0, 0.0 ); cairo_set_source_surface ( d, CacheState.fake_bg, 0.0, 0.0 );
} }
@ -777,39 +866,26 @@ void rofi_view_update ( RofiViewState *state )
} }
cairo_paint ( d ); cairo_paint ( d );
cairo_set_operator ( d, CAIRO_OPERATOR_OVER ); cairo_set_operator ( d, CAIRO_OPERATOR_OVER );
color_background ( d );
cairo_paint ( d );
} }
else { else {
// Paint the background. // Paint the background transparent.
color_background ( d ); cairo_set_source_rgba ( d, 0,0,0,0.0);
cairo_paint ( d ); cairo_paint ( d );
} }
TICK_N ( "Background" ); TICK_N ( "Background" );
color_border ( d );
if ( config.menu_bw > 0 ) {
cairo_save ( d );
cairo_set_line_width ( d, config.menu_bw );
cairo_rectangle ( d,
config.menu_bw / 2.0,
config.menu_bw / 2.0,
state->width - config.menu_bw,
state->height - config.menu_bw );
cairo_stroke ( d );
cairo_restore ( d );
}
// Always paint as overlay over the background. // Always paint as overlay over the background.
cairo_set_operator ( d, CAIRO_OPERATOR_OVER ); cairo_set_operator ( d, CAIRO_OPERATOR_OVER );
widget_draw ( WIDGET ( state->main_box ), d ); widget_draw ( WIDGET ( state->main_window ), d );
if ( state->overlay ) { if ( state->overlay ) {
widget_draw ( WIDGET ( state->overlay ), d ); widget_draw ( WIDGET ( state->overlay ), d );
} }
TICK_N ( "widgets" ); TICK_N ( "widgets" );
cairo_surface_flush ( CacheState.edit_surf ); cairo_surface_flush ( CacheState.edit_surf );
if ( qr ) {
rofi_view_queue_redraw (); rofi_view_queue_redraw ();
}
} }
/** /**
@ -828,9 +904,10 @@ static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t
if ( text != NULL && text[0] != '\0' ) { if ( text != NULL && text[0] != '\0' ) {
unsigned int dl = strlen ( text ); unsigned int dl = strlen ( text );
// Strip new line // Strip new line
while ( dl > 0 && text[dl] == '\n' ) { for ( unsigned int i = 0; i < dl; i++){
text[dl] = '\0'; if ( text[i] == '\n' ){
dl--; dl = i;
}
} }
// Insert string move cursor. // Insert string move cursor.
textbox_insert ( state->text, state->text->cursor, text, dl ); textbox_insert ( state->text, state->text->cursor, text, dl );
@ -865,9 +942,7 @@ static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_
} }
else { else {
xcb_button_press_event_t rel = *xbe; xcb_button_press_event_t rel = *xbe;
rel.event_x -= config.padding; if ( widget_clicked ( WIDGET ( state->main_window ), &rel ) ) {
rel.event_y -= config.padding;
if ( widget_clicked ( WIDGET ( state->main_box ), &rel ) ) {
return; return;
} }
} }
@ -879,6 +954,7 @@ static void _rofi_view_reload_row ( RofiViewState *state )
state->num_lines = mode_get_num_entries ( state->sw ); state->num_lines = mode_get_num_entries ( state->sw );
state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) ); state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) );
state->distance = g_malloc0_n ( state->num_lines, sizeof ( int ) ); state->distance = g_malloc0_n ( state->num_lines, sizeof ( int ) );
listview_set_max_lines ( state->list_view, state->num_lines );
} }
static void rofi_view_refilter ( RofiViewState *state ) static void rofi_view_refilter ( RofiViewState *state )
@ -962,7 +1038,9 @@ static void rofi_view_refilter ( RofiViewState *state )
state->retv = MENU_OK; state->retv = MENU_OK;
state->quit = TRUE; state->quit = TRUE;
} }
if ( config.fixed_num_lines == FALSE && ( CacheState.flags & MENU_NORMAL_WINDOW ) == 0 ) {
// Make sure we enable fixed num lines when in normal window mode.
if ( (CacheState.flags&MENU_NORMAL_WINDOW) == 0 ){
int height = rofi_view_calculate_height ( state ); int height = rofi_view_calculate_height ( state );
if ( height != state->height ) { if ( height != state->height ) {
state->height = height; state->height = height;
@ -1244,6 +1322,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
if ( state->x != xce->x || state->y != xce->y ) { if ( state->x != xce->x || state->y != xce->y ) {
state->x = xce->x; state->x = xce->x;
state->y = xce->y; state->y = xce->y;
widget_queue_redraw ( WIDGET ( state->main_window ) );
} }
if ( state->width != xce->width || state->height != xce->height ) { if ( state->width != xce->width || state->height != xce->height ) {
state->width = xce->width; state->width = xce->width;
@ -1259,7 +1338,8 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height ); CacheState.edit_surf = cairo_xcb_surface_create ( xcb->connection, CacheState.edit_pixmap, visual, state->width, state->height );
CacheState.edit_draw = cairo_create ( CacheState.edit_surf ); CacheState.edit_draw = cairo_create ( CacheState.edit_surf );
widget_resize ( WIDGET ( state->main_box ), state->width - 2 * state->border, state->height - 2 * state->border ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Re-size window based external request: %d %d\n", state->width, state->height);
widget_resize ( WIDGET ( state->main_window ), state->width, state->height );
} }
} }
break; break;
@ -1280,9 +1360,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
state->mouse_seen = TRUE; state->mouse_seen = TRUE;
} }
xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) ev ); xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) ev );
xme.event_x -= config.padding; if ( widget_motion_notify ( WIDGET ( state->main_window ), &xme ) ) {
xme.event_y -= config.padding;
if ( widget_motion_notify ( WIDGET ( state->main_box ), &xme ) ) {
return; return;
} }
break; break;
@ -1340,7 +1418,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
if ( state->refilter ) { if ( state->refilter ) {
rofi_view_refilter ( state ); rofi_view_refilter ( state );
} }
rofi_view_update ( state ); rofi_view_update ( state, TRUE );
if ( ( ev->response_type & ~0x80 ) == XCB_EXPOSE && CacheState.repaint_source == 0 ) { if ( ( ev->response_type & ~0x80 ) == XCB_EXPOSE && CacheState.repaint_source == 0 ) {
CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL ); CacheState.repaint_source = g_idle_add_full ( G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL );
@ -1350,19 +1428,13 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
static int rofi_view_calculate_height ( RofiViewState *state ) static int rofi_view_calculate_height ( RofiViewState *state )
{ {
unsigned int height = 0; unsigned int height = 0;
if ( config.menu_lines == 0 || config.fullscreen == TRUE ) { if ( listview_get_num_lines ( state->list_view ) == 0 || CacheState.fullscreen == TRUE ) {
height = CacheState.mon.h; height = CacheState.mon.h;
return height; return height;
} }
if ( state->filtered_lines == 0 && !config.fixed_num_lines ) {
widget_disable ( WIDGET ( state->input_bar_separator ) ); widget *main_window = WIDGET ( state->main_window );
} height = widget_get_desired_height ( main_window );
else {
widget_enable ( WIDGET ( state->input_bar_separator ) );
}
height = listview_get_desired_height ( state->list_view );
height += box_get_fixed_pixels ( state->main_box );
height += 2 * state->border;
return height; return height;
} }
@ -1411,7 +1483,6 @@ RofiViewState *rofi_view_create ( Mode *sw,
state->skip_absorb = FALSE; state->skip_absorb = FALSE;
//We want to filter on the first run. //We want to filter on the first run.
state->refilter = TRUE; state->refilter = TRUE;
state->border = config.padding + config.menu_bw;
state->finalize = finalize; state->finalize = finalize;
state->mouse_seen = FALSE; state->mouse_seen = FALSE;
@ -1423,115 +1494,91 @@ RofiViewState *rofi_view_create ( Mode *sw,
// Get active monitor size. // Get active monitor size.
TICK_N ( "Get active monitor" ); TICK_N ( "Get active monitor" );
state->main_box = box_create ( BOX_VERTICAL, state->main_window = container_create ( "window" );
state->border, state->border, state->main_box = box_create ( "window.mainbox.box", BOX_VERTICAL );
state->width - 2 * state->border, state->height - 2 * state->border ); container_add ( state->main_window, WIDGET ( state->main_box ) );
box_set_padding ( state->main_box, config.line_margin );
// we need this at this point so we can get height.
unsigned int line_height = textbox_get_estimated_char_height ();
rofi_view_calculate_window_and_element_width ( state );
state->input_bar = box_create ( BOX_HORIZONTAL, 0, 0, state->width - state->border, line_height );
//box_set_padding ( state->input_bar, config.line_margin );
state->input_bar_separator = separator_create ( S_HORIZONTAL, 2 );
separator_set_line_style_from_string ( state->input_bar_separator, config.separator_style );
state->input_bar = box_create ( "window.mainbox.inputbar.box", BOX_HORIZONTAL );
// Only enable widget when sidebar is enabled. // Only enable widget when sidebar is enabled.
if ( config.sidebar_mode ) { if ( config.sidebar_mode ) {
state->sidebar_bar = box_create ( BOX_HORIZONTAL, 0, 0, state->width - 2 * state->border, line_height ); state->sidebar_bar = box_create ( "window.mainbox.sidebar.box", BOX_HORIZONTAL );
box_set_padding ( state->sidebar_bar, config.line_margin ); box_add ( state->main_box, WIDGET ( state->sidebar_bar ), FALSE, 10 );
separator *sep = separator_create ( S_HORIZONTAL, 2 );
separator_set_line_style_from_string ( sep, config.separator_style );
box_add ( state->main_box, WIDGET ( state->sidebar_bar ), FALSE, TRUE );
box_add ( state->main_box, WIDGET ( sep ), FALSE, TRUE );
state->num_modi = rofi_get_num_enabled_modi (); state->num_modi = rofi_get_num_enabled_modi ();
state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) ); state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) );
for ( unsigned int j = 0; j < state->num_modi; j++ ) { for ( unsigned int j = 0; j < state->num_modi; j++ ) {
const Mode * mode = rofi_get_mode ( j ); const Mode * mode = rofi_get_mode ( j );
state->modi[j] = textbox_create ( TB_CENTER, 0, 0, 0, 0, ( mode == state->sw ) ? HIGHLIGHT : NORMAL, state->modi[j] = textbox_create ( "window.mainbox.sidebar.button", TB_CENTER|TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL,
mode_get_display_name ( mode ) ); mode_get_display_name ( mode ) );
box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, FALSE ); box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j );
widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state ); widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state );
} }
} }
int end = ( config.location == WL_EAST_SOUTH || config.location == WL_SOUTH || config.location == WL_SOUTH_WEST ); int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location );
box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end ); int end = ( location == WL_SOUTH_EAST || location == WL_SOUTH || location == WL_SOUTH_WEST );
box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end?9:0 );
state->case_indicator = textbox_create ( TB_AUTOWIDTH, 0, 0, 0, line_height, NORMAL, "*" ); state->case_indicator = textbox_create ( "window.mainbox.inputbar.case-indicator", TB_AUTOWIDTH|TB_AUTOHEIGHT, NORMAL, "*" );
// Add small separator between case indicator and text box. // Add small separator between case indicator and text box.
box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, TRUE ); box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, 3 );
// Prompt box. // Prompt box.
state->prompt = textbox_create ( TB_AUTOWIDTH, 0, 0, 0, line_height, NORMAL, "" ); state->prompt = textbox_create ( "window.mainbox.inputbar.prompt",TB_AUTOWIDTH|TB_AUTOHEIGHT, NORMAL, "" );
rofi_view_update_prompt ( state ); rofi_view_update_prompt ( state );
box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, FALSE ); box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, 1 );
// Entry box // Entry box
TextboxFlags tfl = TB_EDITABLE; TextboxFlags tfl = TB_EDITABLE;
tfl |= ( ( menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0; tfl |= ( ( menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0;
state->text = textbox_create ( tfl, 0, 0, 0, line_height, NORMAL, input ); state->text = textbox_create ( "window.mainbox.inputbar.entry", tfl|TB_AUTOHEIGHT, NORMAL, input );
box_add ( state->input_bar, WIDGET ( state->text ), TRUE, FALSE ); box_add ( state->input_bar, WIDGET ( state->text ), TRUE, 2 );
textbox_text ( state->case_indicator, get_matching_state () ); textbox_text ( state->case_indicator, get_matching_state () );
if ( message ) { if ( message ) {
textbox *message_tb = textbox_create ( TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, 0, 0, container *box = container_create ( "window.mainbox.message.box" );
state->width - ( 2 * ( state->border ) ), -1, NORMAL, message ); textbox *message_tb = textbox_create ( "window.mainbox.message.textbox", TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, message );
separator *sep = separator_create ( S_HORIZONTAL, 2 ); container_add ( box, WIDGET (message_tb) );
box_add ( state->main_box, WIDGET ( sep ), FALSE, end); box_add ( state->main_box, WIDGET ( box ), FALSE, end?8:2);
box_add ( state->main_box, WIDGET ( message_tb ), FALSE, end);
separator_set_line_style_from_string ( sep, config.separator_style );
} }
box_add ( state->main_box, WIDGET ( state->input_bar_separator ), FALSE, end );
state->overlay = textbox_create ( TB_AUTOWIDTH, 0, 0, 20, line_height, URGENT, "blaat" ); state->overlay = textbox_create ( "window.overlay", TB_AUTOWIDTH|TB_AUTOHEIGHT, URGENT, "blaat" );
widget_disable ( WIDGET ( state->overlay ) ); widget_disable ( WIDGET ( state->overlay ) );
state->list_view = listview_create ( update_callback, state, config.element_height ); state->list_view = listview_create ( "window.mainbox.listview", update_callback, state, config.element_height, end );
// Set configuration // Set configuration
listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR ); listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR );
listview_set_padding ( state->list_view, config.line_margin );
listview_set_max_lines ( state->list_view, config.menu_lines );
listview_set_max_columns ( state->list_view, config.menu_columns );
listview_set_fixed_num_lines ( state->list_view, config.fixed_num_lines );
listview_set_hide_scrollbar ( state->list_view, !config.hide_scrollbar );
listview_set_scrollbar_width ( state->list_view, config.scrollbar_width );
listview_set_cycle ( state->list_view, config.cycle );
listview_set_scroll_type ( state->list_view, config.scroll_method ); listview_set_scroll_type ( state->list_view, config.scroll_method );
listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state ); listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state );
box_add ( state->main_box, WIDGET ( state->list_view ), TRUE, FALSE ); int lines = rofi_theme_get_integer ( WIDGET (state->list_view ), "lines", config.menu_lines );
listview_set_num_lines ( state->list_view, lines );
listview_set_max_lines ( state->list_view, state->num_lines );
box_add ( state->main_box, WIDGET ( state->list_view ), TRUE, 3);
// Height of a row.
if ( config.menu_lines == 0 || config.fullscreen ) {
state->height = CacheState.mon.h;
// Autosize it.
config.fixed_num_lines = TRUE;
}
// filtered list // filtered list
state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) ); state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) );
state->distance = (int *) g_malloc0_n ( state->num_lines, sizeof ( int ) ); state->distance = (int *) g_malloc0_n ( state->num_lines, sizeof ( int ) );
state->height = rofi_view_calculate_height ( state ); rofi_view_calculate_window_width ( state );
// Need to resize otherwise calculated desired height is wrong.
widget_resize ( WIDGET ( state->main_window ), state->width, 100);
// Only needed when window is fixed size.
if (( CacheState.flags & MENU_NORMAL_WINDOW ) == MENU_NORMAL_WINDOW ) {
listview_set_fixed_num_lines ( state->list_view );
rofi_view_window_update_size ( state );
}
// Move the window to the correct x,y position. // Move the window to the correct x,y position.
rofi_view_calculate_window_position ( state ); rofi_view_calculate_window_position ( state );
rofi_view_window_update_size ( state );
// Update.
//state->selected = 0;
state->quit = FALSE; state->quit = FALSE;
rofi_view_refilter ( state ); rofi_view_refilter ( state );
rofi_view_update ( state, TRUE );
rofi_view_update ( state );
xcb_map_window ( xcb->connection, CacheState.main_window ); xcb_map_window ( xcb->connection, CacheState.main_window );
widget_queue_redraw ( WIDGET ( state->main_box ) ); widget_queue_redraw ( WIDGET ( state->main_window ) );
xcb_flush ( xcb->connection ); xcb_flush ( xcb->connection );
if ( xcb->sncontext != NULL ) { if ( xcb->sncontext != NULL ) {
sn_launchee_context_complete ( xcb->sncontext ); sn_launchee_context_complete ( xcb->sncontext );
@ -1543,22 +1590,27 @@ int rofi_view_error_dialog ( const char *msg, int markup )
{ {
RofiViewState *state = __rofi_view_state_create (); RofiViewState *state = __rofi_view_state_create ();
state->retv = MENU_CANCEL; state->retv = MENU_CANCEL;
state->border = config.padding + config.menu_bw;
state->menu_flags = MENU_ERROR_DIALOG; state->menu_flags = MENU_ERROR_DIALOG;
state->finalize = process_result; state->finalize = process_result;
rofi_view_calculate_window_and_element_width ( state ); state->main_window = container_create ( "window" );
state->main_box = box_create ( BOX_VERTICAL, state->main_box = box_create ( "window.mainbox.message.box", BOX_VERTICAL);
state->border, state->border, container_add ( state->main_window, WIDGET ( state->main_box ) );
state->width - 2 * state->border, state->height - 2 * state->border ); state->text = textbox_create ( "window.mainbox.message.textbox", ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ),
state->text = textbox_create ( ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ), NORMAL, ( msg != NULL ) ? msg : "" );
( state->border ), ( state->border ), box_add ( state->main_box, WIDGET ( state->text ), TRUE, 1 );
( state->width - ( 2 * ( state->border ) ) ), 1, NORMAL, ( msg != NULL ) ? msg : "" );
box_add ( state->main_box, WIDGET ( state->text ), TRUE, FALSE );
unsigned int line_height = textbox_get_height ( state->text );
// Make sure we enable fixed num lines when in normal window mode.
if ( (CacheState.flags&MENU_NORMAL_WINDOW) == MENU_NORMAL_WINDOW){
listview_set_fixed_num_lines ( state->list_view );
}
rofi_view_calculate_window_width ( state );
// Need to resize otherwise calculated desired height is wrong.
widget_resize ( WIDGET ( state->main_window ), state->width, 100);
unsigned int line_height = textbox_get_height ( state->text );
// resize window vertically to suit // resize window vertically to suit
state->height = line_height + ( state->border ) * 2; state->height = line_height + widget_padding_get_padding_height ( WIDGET(state->main_window) );
// Calculte window position. // Calculte window position.
rofi_view_calculate_window_position ( state ); rofi_view_calculate_window_position ( state );
@ -1568,7 +1620,7 @@ int rofi_view_error_dialog ( const char *msg, int markup )
// Display it. // Display it.
xcb_map_window ( xcb->connection, CacheState.main_window ); xcb_map_window ( xcb->connection, CacheState.main_window );
widget_queue_redraw ( WIDGET ( state->main_box ) ); widget_queue_redraw ( WIDGET ( state->main_window ) );
if ( xcb->sncontext != NULL ) { if ( xcb->sncontext != NULL ) {
sn_launchee_context_complete ( xcb->sncontext ); sn_launchee_context_complete ( xcb->sncontext );
@ -1675,9 +1727,17 @@ void rofi_view_set_overlay ( RofiViewState *state, const char *text )
} }
widget_enable ( WIDGET ( state->overlay ) ); widget_enable ( WIDGET ( state->overlay ) );
textbox_text ( state->overlay, text ); textbox_text ( state->overlay, text );
unsigned int x_offset = state->width - ( 2 * state->border ) - widget_get_width ( WIDGET ( state->case_indicator ) ); int x_offset = widget_get_width ( WIDGET(state->main_window) );
// Within padding of window.
x_offset -= widget_padding_get_right ( WIDGET (state->main_window) );
// Within the border of widget.
x_offset -= widget_padding_get_right ( WIDGET (state->main_box ) );
x_offset -= widget_padding_get_right ( WIDGET (state->input_bar ) );
x_offset -= widget_get_width ( WIDGET ( state->case_indicator ) );
x_offset -= widget_get_width ( WIDGET ( state->overlay ) ); x_offset -= widget_get_width ( WIDGET ( state->overlay ) );
widget_move ( WIDGET ( state->overlay ), x_offset, state->border ); int top_offset = widget_padding_get_top ( WIDGET (state->main_window) );
top_offset += widget_padding_get_top ( WIDGET (state->main_box ) );
widget_move ( WIDGET ( state->overlay ), x_offset, top_offset );
// We want to queue a repaint. // We want to queue a repaint.
rofi_view_queue_redraw ( ); rofi_view_queue_redraw ( );
} }
@ -1707,7 +1767,7 @@ void rofi_view_switch_mode ( RofiViewState *state, Mode *mode )
state->reload = TRUE; state->reload = TRUE;
state->refilter = TRUE; state->refilter = TRUE;
rofi_view_refilter ( state ); rofi_view_refilter ( state );
rofi_view_update ( state ); rofi_view_update ( state, TRUE );
} }
xcb_window_t rofi_view_get_window ( void ) xcb_window_t rofi_view_get_window ( void )

View file

@ -29,26 +29,75 @@
#include "widgets/widget.h" #include "widgets/widget.h"
#include "widgets/widget-internal.h" #include "widgets/widget-internal.h"
#include "widgets/box.h" #include "widgets/box.h"
#include "theme.h"
#define LOG_DOMAIN "Widgets.Box" #define LOG_DOMAIN "Widgets.Box"
/** Default spacing used in the box*/
#define DEFAULT_SPACING 2
struct _box struct _box
{ {
widget widget; widget widget;
boxType type; boxType type;
int max_size; int max_size;
// Padding between elements // Padding between elements
int padding; Distance spacing;
GList *children; GList *children;
}; };
static void box_update ( widget *wid ); static void box_update ( widget *wid );
static int box_get_desired_height ( widget *wid )
{
box *b = (box *)wid;
int spacing = distance_get_pixel ( b->spacing, b->type == BOX_VERTICAL? ORIENTATION_VERTICAL:ORIENTATION_HORIZONTAL );
int active_widgets = 0;
int height = 0;
if ( b->type == BOX_VERTICAL ){
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data;
if ( !child->enabled ) {
continue;
}
active_widgets++;
if ( child->expand == TRUE ) {
height += widget_get_desired_height ( child );
continue;
}
height += widget_get_desired_height ( child );
}
if ( active_widgets > 0 ){
height += (active_widgets - 1)*spacing;
}
} else {
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data;
if ( !child->enabled ) {
continue;
}
height = MAX ( widget_get_desired_height ( child ), height );
}
}
height += widget_padding_get_padding_height ( wid );
return height;
}
static void vert_calculate_size ( box *b ) static void vert_calculate_size ( box *b )
{ {
int spacing = distance_get_pixel ( b->spacing, ORIENTATION_VERTICAL );
int expanding_widgets = 0; int expanding_widgets = 0;
int active_widgets = 0; int active_widgets = 0;
int rem_width = widget_padding_get_remaining_width ( WIDGET (b) );
int rem_height = widget_padding_get_remaining_height ( WIDGET (b) );
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data;
if ( child->enabled && child->expand == FALSE ){
widget_resize ( child, rem_width, widget_get_desired_height (child) );
}
}
b->max_size = 0; b->max_size = 0;
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data; widget * child = (widget *) iter->data;
@ -60,17 +109,21 @@ static void vert_calculate_size ( box *b )
expanding_widgets++; expanding_widgets++;
continue; continue;
} }
if ( child->h > 0 ){
b->max_size += child->h; b->max_size += child->h;
} }
b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * b->padding ) ); }
if ( b->max_size > b->widget.h ) { if ( active_widgets > 0 ){
b->max_size += ( active_widgets - 1 ) * spacing;
}
if ( b->max_size > rem_height ) {
b->max_size = rem_height;
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h );
return; return;
} }
if ( active_widgets > 0 ) { if ( active_widgets > 0 ) {
int bottom = b->widget.h; int top = widget_padding_get_top ( WIDGET ( b ) );
int top = 0; double rem = rem_height - b->max_size;
double rem = b->widget.h - b->max_size;
int index = 0; int index = 0;
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data; widget * child = (widget *) iter->data;
@ -80,40 +133,35 @@ static void vert_calculate_size ( box *b )
if ( child->expand == TRUE ) { if ( child->expand == TRUE ) {
// Re-calculate to avoid round issues leaving one pixel left. // Re-calculate to avoid round issues leaving one pixel left.
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index ); int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
if ( child->end ) { widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
bottom -= expanding_widgets_size;
widget_move ( child, child->x, bottom );
widget_resize ( child, b->widget.w, expanding_widgets_size );
bottom -= b->padding;
}
else {
widget_move ( child, child->x, top );
top += expanding_widgets_size; top += expanding_widgets_size;
widget_resize ( child, b->widget.w, expanding_widgets_size ); widget_resize ( child, rem_width, expanding_widgets_size );
top += b->padding; top += spacing;
}
rem -= expanding_widgets_size; rem -= expanding_widgets_size;
index++; index++;
} }
else if ( child->end ) {
bottom -= widget_get_height ( child );
widget_move ( child, child->x, bottom );
widget_resize ( child, b->widget.w, child->h );
bottom -= b->padding;
}
else { else {
widget_move ( child, child->x, top ); widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
top += widget_get_height ( child ); top += widget_get_height ( child );
widget_resize ( child, b->widget.w, child->h ); top += spacing;
top += b->padding;
} }
} }
} }
b->max_size += widget_padding_get_padding_height ( WIDGET (b) );
} }
static void hori_calculate_size ( box *b ) static void hori_calculate_size ( box *b )
{ {
int spacing = distance_get_pixel ( b->spacing, ORIENTATION_HORIZONTAL );
int expanding_widgets = 0; int expanding_widgets = 0;
int active_widgets = 0; int active_widgets = 0;
int rem_width = widget_padding_get_remaining_width ( WIDGET (b) );
int rem_height = widget_padding_get_remaining_height ( WIDGET (b) );
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data;
if ( child->enabled && child->expand == FALSE ){
widget_resize ( child, child->w, rem_height );
}
}
b->max_size = 0; b->max_size = 0;
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data; widget * child = (widget *) iter->data;
@ -126,17 +174,19 @@ static void hori_calculate_size ( box *b )
continue; continue;
} }
// Size used by fixed width widgets. // Size used by fixed width widgets.
if ( child->h > 0 ){
b->max_size += child->w; b->max_size += child->w;
} }
b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * b->padding ) ); }
if ( b->max_size > b->widget.w ) { b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * spacing ) );
if ( b->max_size > (rem_width)) {
b->max_size = rem_width;
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (width) for box: %d %d", b->max_size, b->widget.w ); g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Widgets to large (width) for box: %d %d", b->max_size, b->widget.w );
return; return;
} }
if ( active_widgets > 0 ) { if ( active_widgets > 0 ) {
int right = b->widget.w; int left = widget_padding_get_left ( WIDGET (b) );
int left = 0; double rem = rem_width - b->max_size;
double rem = b->widget.w - b->max_size;
int index = 0; int index = 0;
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data; widget * child = (widget *) iter->data;
@ -146,52 +196,30 @@ static void hori_calculate_size ( box *b )
if ( child->expand == TRUE ) { if ( child->expand == TRUE ) {
// Re-calculate to avoid round issues leaving one pixel left. // Re-calculate to avoid round issues leaving one pixel left.
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index ); int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
if ( child->end ) { widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
right -= expanding_widgets_size;
widget_move ( child, right, child->y );
widget_resize ( child, expanding_widgets_size, b->widget.h );
right -= b->padding;
}
else {
widget_move ( child, left, child->y );
left += expanding_widgets_size; left += expanding_widgets_size;
widget_resize ( child, expanding_widgets_size, b->widget.h ); widget_resize ( child, expanding_widgets_size, rem_height );
left += b->padding; left += spacing;
}
rem -= expanding_widgets_size; rem -= expanding_widgets_size;
index++; index++;
} }
else if ( child->end ) {
right -= widget_get_width ( child );
widget_move ( child, right, child->y );
widget_resize ( child, child->w, b->widget.h );
right -= b->padding;
}
else { else {
widget_move ( child, left, child->y ); widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
left += widget_get_width ( child ); left += widget_get_width ( child );
widget_resize ( child, child->w, b->widget.h ); left += spacing;
left += b->padding;
} }
} }
} }
b->max_size += widget_padding_get_padding_width ( WIDGET ( b ) );
} }
static void box_draw ( widget *wid, cairo_t *draw ) static void box_draw ( widget *wid, cairo_t *draw )
{ {
box *b = (box *) wid; box *b = (box *) wid;
// Store current state.
cairo_save ( draw );
// Define a clipmask so we won't draw outside out widget.
cairo_rectangle ( draw, wid->x, wid->y, wid->w, wid->h );
cairo_clip ( draw );
// Set new x/y possition.
cairo_translate ( draw, wid->x, wid->y );
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
widget * child = (widget *) iter->data; widget * child = (widget *) iter->data;
widget_draw ( child, draw ); widget_draw ( child, draw );
} }
cairo_restore ( draw );
} }
static void box_free ( widget *wid ) static void box_free ( widget *wid )
@ -206,15 +234,34 @@ static void box_free ( widget *wid )
g_free ( b ); g_free ( b );
} }
void box_add ( box *box, widget *child, gboolean expand, gboolean end ) static int box_sort_children ( gconstpointer a, gconstpointer b )
{
widget *child_a = (widget*)a;
widget *child_b = (widget*)b;
return child_a->index - child_b->index;
}
void box_add ( box *box, widget *child, gboolean expand, int index )
{ {
if ( box == NULL ) { if ( box == NULL ) {
return; return;
} }
child->expand = expand; // Make sure box is width/heigh enough.
child->end = end; if ( box->type == BOX_VERTICAL){
int width=box->widget.w;
width = MAX ( width, child->w+widget_padding_get_padding_width ( WIDGET ( box ) ));
box->widget.w = width;
} else {
int height = box->widget.h;
height = MAX (height, child->h+widget_padding_get_padding_height ( WIDGET ( box )));
box->widget.h = height;
}
child->expand = rofi_theme_get_boolean ( child, "expand", expand);
child->index = rofi_theme_get_integer_exact ( child, "index" , index );
child->parent = WIDGET ( box ); child->parent = WIDGET ( box );
box->children = g_list_append ( box->children, (void *) child ); box->children = g_list_append ( box->children, (void *) child );
box->children = g_list_sort ( box->children, box_sort_children );
widget_update ( WIDGET ( box ) ); widget_update ( WIDGET ( box ) );
} }
@ -263,22 +310,22 @@ static gboolean box_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme
return FALSE; return FALSE;
} }
box * box_create ( boxType type, short x, short y, short w, short h ) box * box_create ( const char *name, boxType type )
{ {
box *b = g_malloc0 ( sizeof ( box ) ); box *b = g_malloc0 ( sizeof ( box ) );
// Initialize widget.
widget_init ( WIDGET(b), name );
b->type = type; b->type = type;
b->widget.x = x;
b->widget.y = y;
b->widget.w = w;
b->widget.h = h;
b->widget.draw = box_draw; b->widget.draw = box_draw;
b->widget.free = box_free; b->widget.free = box_free;
b->widget.resize = box_resize; b->widget.resize = box_resize;
b->widget.update = box_update; b->widget.update = box_update;
b->widget.clicked = box_clicked; b->widget.clicked = box_clicked;
b->widget.motion_notify = box_motion_notify; b->widget.motion_notify = box_motion_notify;
b->widget.get_desired_height = box_get_desired_height;
b->widget.enabled = TRUE; b->widget.enabled = TRUE;
b->spacing = rofi_theme_get_distance ( WIDGET(b), "spacing", DEFAULT_SPACING );
return b; return b;
} }
@ -302,11 +349,3 @@ int box_get_fixed_pixels ( box *box )
} }
return 0; return 0;
} }
void box_set_padding ( box * box, unsigned int padding )
{
if ( box != NULL ) {
box->padding = padding;
widget_queue_redraw ( WIDGET ( box ) );
}
}

148
source/widgets/container.c Normal file
View file

@ -0,0 +1,148 @@
/**
* rofi
*
* MIT/X11 License
* Modified 2016-2017 Qball Cow <qball@gmpclient.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include "widgets/widget.h"
#include "widgets/widget-internal.h"
#include "widgets/container.h"
#include "theme.h"
#define LOG_DOMAIN "Widgets.Window"
/** The default border width of the container */
#define DEFAULT_BORDER_WIDTH 2
struct _window
{
widget widget;
widget *child;
};
static void container_update ( widget *wid );
static int container_get_desired_height ( widget *widget )
{
container *b = (container *) widget;
int height = 0;
if ( b->child ) {
height += widget_get_desired_height ( b->child );
}
height += widget_padding_get_padding_height ( widget );
return height;
}
static void container_draw ( widget *wid, cairo_t *draw )
{
container *b = (container *) wid;
widget_draw ( b->child, draw );
}
static void container_free ( widget *wid )
{
container *b = (container *) wid;
widget_free ( b->child );
g_free ( b );
}
void container_add ( container *container, widget *child )
{
if ( container == NULL ) {
return;
}
container->child = child;
child->parent = WIDGET ( container );
widget_update ( WIDGET ( container ) );
}
static void container_resize ( widget *widget, short w, short h )
{
container *b = (container *) widget;
if ( b->widget.w != w || b->widget.h != h ) {
b->widget.w = w;
b->widget.h = h;
widget_update ( widget );
}
}
static gboolean container_clicked ( widget *wid, xcb_button_press_event_t *xbe, G_GNUC_UNUSED void *udata )
{
container *b = (container *) wid;
if ( widget_intersect ( b->child, xbe->event_x, xbe->event_y ) ) {
xcb_button_press_event_t rel = *xbe;
rel.event_x -= b->child->x;
rel.event_y -= b->child->y;
return widget_clicked ( b->child, &rel );
}
return FALSE;
}
static gboolean container_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme )
{
container *b = (container *) wid;
if ( widget_intersect ( b->child, xme->event_x, xme->event_y ) ) {
xcb_motion_notify_event_t rel = *xme;
rel.event_x -= b->child->x;
rel.event_y -= b->child->y;
return widget_motion_notify ( b->child, &rel );
}
return FALSE;
}
container * container_create ( const char *name )
{
container *b = g_malloc0 ( sizeof ( container ) );
// Initialize widget.
widget_init ( WIDGET(b), name );
b->widget.draw = container_draw;
b->widget.free = container_free;
b->widget.resize = container_resize;
b->widget.update = container_update;
b->widget.clicked = container_clicked;
b->widget.motion_notify = container_motion_notify;
b->widget.get_desired_height = container_get_desired_height;
b->widget.enabled = TRUE;
return b;
}
static void container_update ( widget *wid )
{
container *b = (container *) wid;
if ( b->child && b->child->enabled ){
widget_resize ( WIDGET ( b->child ),
widget_padding_get_remaining_width (WIDGET(b)),
widget_padding_get_remaining_height (WIDGET(b))
);
widget_move ( WIDGET ( b->child ),
widget_padding_get_left (WIDGET(b)),
widget_padding_get_top (WIDGET(b))
);
}
}

View file

@ -29,6 +29,11 @@
#include <widgets/listview.h> #include <widgets/listview.h>
#include <widgets/scrollbar.h> #include <widgets/scrollbar.h>
#include "settings.h"
#include "theme.h"
#define DEFAULT_SPACING 2
struct _listview struct _listview
{ {
widget widget; widget widget;
@ -51,10 +56,14 @@ struct _listview
unsigned int req_elements; unsigned int req_elements;
unsigned int cur_elements; unsigned int cur_elements;
unsigned int padding; Distance spacing;
unsigned int menu_lines; unsigned int menu_lines;
unsigned int max_displayed_lines;
unsigned int menu_columns; unsigned int menu_columns;
unsigned int fixed_num_lines; unsigned int fixed_num_lines;
unsigned int dynamic;
unsigned int eh;
unsigned int reverse;
gboolean cycle; gboolean cycle;
gboolean multi_select; gboolean multi_select;
@ -71,8 +80,13 @@ struct _listview
xcb_timestamp_t last_click; xcb_timestamp_t last_click;
listview_mouse_activated_cb mouse_activated; listview_mouse_activated_cb mouse_activated;
void *mouse_activated_data; void *mouse_activated_data;
char *listview_name;
}; };
static int listview_get_desired_height ( widget *wid );
static void listview_free ( widget *wid ) static void listview_free ( widget *wid )
{ {
listview *lv = (listview *) wid; listview *lv = (listview *) wid;
@ -81,6 +95,7 @@ static void listview_free ( widget *wid )
} }
g_free ( lv->boxes ); g_free ( lv->boxes );
g_free( lv->listview_name );
widget_free ( WIDGET ( lv->scrollbar ) ); widget_free ( WIDGET ( lv->scrollbar ) );
g_free ( lv ); g_free ( lv );
} }
@ -152,24 +167,40 @@ static void listview_draw ( widget *wid, cairo_t *draw )
// Set these all together to make sure they update consistently. // Set these all together to make sure they update consistently.
scrollbar_set_max_value ( lv->scrollbar, lv->req_elements ); scrollbar_set_max_value ( lv->scrollbar, lv->req_elements );
scrollbar_set_handle_length ( lv->scrollbar, lv->cur_columns * lv->max_rows ); scrollbar_set_handle_length ( lv->scrollbar, lv->cur_columns * lv->max_rows );
if ( lv->reverse ) {
scrollbar_set_handle ( lv->scrollbar, lv->req_elements - lv->selected -1 );
} else {
scrollbar_set_handle ( lv->scrollbar, lv->selected ); scrollbar_set_handle ( lv->scrollbar, lv->selected );
}
lv->last_offset = offset; lv->last_offset = offset;
int spacing_vert = distance_get_pixel ( lv->spacing, ORIENTATION_VERTICAL );
int spacing_hori = distance_get_pixel ( lv->spacing, ORIENTATION_HORIZONTAL );
int left_offset = widget_padding_get_left ( wid );
int top_offset = widget_padding_get_top ( wid );
if ( lv->scrollbar->widget.index == 0 ) {
left_offset += spacing_hori + lv->scrollbar->widget.w;
}
if ( lv->cur_elements > 0 && lv->max_rows > 0 ) { if ( lv->cur_elements > 0 && lv->max_rows > 0 ) {
cairo_save ( draw );
// Set new x/y possition. // Set new x/y possition.
cairo_translate ( draw, wid->x, wid->y );
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset ); unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset );
if ( lv->rchanged ) { if ( lv->rchanged ) {
unsigned int width = lv->widget.w - lv->padding * ( lv->cur_columns - 1 ); unsigned int width = lv->widget.w - spacing_hori * ( lv->cur_columns - 1 );
width -= widget_padding_get_padding_width ( wid );
if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) ) { if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) ) {
width -= lv->padding; width -= spacing_hori;
width -= widget_get_width ( WIDGET ( lv->scrollbar ) ); width -= widget_get_width ( WIDGET ( lv->scrollbar ) );
} }
unsigned int element_width = ( width ) / lv->cur_columns; unsigned int element_width = ( width ) / lv->cur_columns;
for ( unsigned int i = 0; i < max; i++ ) { for ( unsigned int i = 0; i < max; i++ ) {
unsigned int ex = ( ( i ) / lv->max_rows ) * ( element_width + lv->padding ); unsigned int ex = left_offset + ( ( i ) / lv->max_rows ) * ( element_width + spacing_hori );
unsigned int ey = ( ( i ) % lv->max_rows ) * ( lv->element_height + lv->padding ); if ( lv->reverse ) {
unsigned int ey = wid->h-(widget_padding_get_bottom ( wid ) + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert ))-lv->element_height;
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height ); textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
} else {
unsigned int ey = top_offset + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert );
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
}
update_element ( lv, i, i + offset, TRUE ); update_element ( lv, i, i + offset, TRUE );
widget_draw ( WIDGET ( lv->boxes[i] ), draw ); widget_draw ( WIDGET ( lv->boxes[i] ), draw );
@ -182,9 +213,8 @@ static void listview_draw ( widget *wid, cairo_t *draw )
widget_draw ( WIDGET ( lv->boxes[i] ), draw ); widget_draw ( WIDGET ( lv->boxes[i] ), draw );
} }
} }
widget_draw ( WIDGET ( lv->scrollbar ), draw );
cairo_restore ( draw );
} }
widget_draw ( WIDGET ( lv->scrollbar ), draw );
} }
static void listview_recompute_elements ( listview *lv ) static void listview_recompute_elements ( listview *lv )
@ -208,7 +238,9 @@ static void listview_recompute_elements ( listview *lv )
if ( newne > 0 ) { if ( newne > 0 ) {
for ( unsigned int i = lv->cur_elements; i < newne; i++ ) { for ( unsigned int i = lv->cur_elements; i < newne; i++ ) {
TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0; TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0;
lv->boxes[i] = textbox_create ( flags, 0, 0, 0, lv->element_height, NORMAL, "" ); char *name = g_strjoin (".", lv->listview_name,"element", NULL);
lv->boxes[i] = textbox_create ( name, flags, NORMAL, "" );
g_free ( name );
} }
} }
lv->rchanged = TRUE; lv->rchanged = TRUE;
@ -244,11 +276,21 @@ static void listview_resize ( widget *wid, short w, short h )
listview *lv = (listview *) wid; listview *lv = (listview *) wid;
lv->widget.w = MAX ( 0, w ); lv->widget.w = MAX ( 0, w );
lv->widget.h = MAX ( 0, h ); lv->widget.h = MAX ( 0, h );
lv->max_rows = ( lv->padding + lv->widget.h ) / ( lv->element_height + lv->padding ); int height = lv->widget.h - widget_padding_get_padding_height ( WIDGET (lv) );
int spacing_vert = distance_get_pixel ( lv->spacing, ORIENTATION_VERTICAL );
lv->max_rows = ( spacing_vert + height ) / ( lv->element_height + spacing_vert );
lv->max_elements = lv->max_rows * lv->menu_columns; lv->max_elements = lv->max_rows * lv->menu_columns;
widget_move ( WIDGET ( lv->scrollbar ), lv->widget.w - widget_get_width ( WIDGET ( lv->scrollbar ) ), 0 ); if ( lv->scrollbar->widget.index == 0 ){
widget_resize ( WIDGET ( lv->scrollbar ), widget_get_width ( WIDGET ( lv->scrollbar ) ), h ); widget_move ( WIDGET ( lv->scrollbar ),
widget_padding_get_left ( WIDGET ( lv ) ),
widget_padding_get_top ( WIDGET ( lv ) ) );
} else {
widget_move ( WIDGET ( lv->scrollbar ),
lv->widget.w - widget_padding_get_right ( WIDGET ( lv ) ) - widget_get_width ( WIDGET ( lv->scrollbar ) ),
widget_padding_get_top ( WIDGET (lv ) ));
}
widget_resize ( WIDGET ( lv->scrollbar ), widget_get_width ( WIDGET ( lv->scrollbar ) ), height );
listview_recompute_elements ( lv ); listview_recompute_elements ( lv );
widget_queue_redraw ( wid ); widget_queue_redraw ( wid );
@ -310,24 +352,49 @@ static gboolean listview_motion_notify ( widget *wid, xcb_motion_notify_event_t
return FALSE; return FALSE;
} }
listview *listview_create ( listview_update_callback cb, void *udata, unsigned int eh ) listview *listview_create ( const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse )
{ {
listview *lv = g_malloc0 ( sizeof ( listview ) ); listview *lv = g_malloc0 ( sizeof ( listview ) );
gchar *box = g_strjoin (".", name, "box", NULL );
widget_init ( WIDGET ( lv ), box );
g_free(box);
lv->listview_name = g_strdup ( name );
lv->widget.free = listview_free; lv->widget.free = listview_free;
lv->widget.resize = listview_resize; lv->widget.resize = listview_resize;
lv->widget.draw = listview_draw; lv->widget.draw = listview_draw;
lv->widget.clicked = listview_clicked; lv->widget.clicked = listview_clicked;
lv->widget.motion_notify = listview_motion_notify; lv->widget.motion_notify = listview_motion_notify;
lv->widget.get_desired_height = listview_get_desired_height;
lv->widget.enabled = TRUE; lv->widget.enabled = TRUE;
lv->eh = eh;
lv->scrollbar = scrollbar_create ( 0, 0, 4, 0 ); char *n = g_strjoin(".", lv->listview_name,"scrollbar", NULL);
lv->scrollbar = scrollbar_create ( n );
// Default position on right.
lv->scrollbar->widget.index = rofi_theme_get_integer_exact ( WIDGET (lv->scrollbar), "index", 1);
g_free(n);
widget_set_clicked_handler ( WIDGET ( lv->scrollbar ), listview_scrollbar_clicked, lv ); widget_set_clicked_handler ( WIDGET ( lv->scrollbar ), listview_scrollbar_clicked, lv );
lv->scrollbar->widget.parent = WIDGET ( lv ); lv->scrollbar->widget.parent = WIDGET ( lv );
// Calculate height of an element. // Calculate height of an element.
lv->element_height = textbox_get_estimated_char_height () * eh; //
char *tb_name = g_strjoin (".", lv->listview_name,"element", NULL);
textbox *tb = textbox_create ( tb_name, 0, NORMAL, "" );
lv->element_height = textbox_get_estimated_height (tb, lv->eh);
g_free(tb_name);
lv->callback = cb; lv->callback = cb;
lv->udata = udata; lv->udata = udata;
// Some settings.
lv->spacing = rofi_theme_get_distance ( WIDGET ( lv ), "spacing", DEFAULT_SPACING );
lv->menu_columns = rofi_theme_get_integer ( WIDGET ( lv ), "columns", config.menu_columns );
lv->fixed_num_lines = rofi_theme_get_boolean ( WIDGET ( lv ), "fixed-height", config.fixed_num_lines );
lv->dynamic = rofi_theme_get_boolean ( WIDGET ( lv ), "dynamic", TRUE );
lv->reverse = rofi_theme_get_boolean ( WIDGET ( lv ), "reverse", reverse );
listview_set_show_scrollbar ( lv, rofi_theme_get_boolean ( WIDGET ( lv ), "scrollbar", !config.hide_scrollbar ));
lv->cycle = rofi_theme_get_boolean ( WIDGET ( lv ), "cycle", config.cycle );
return lv; return lv;
} }
@ -335,7 +402,7 @@ listview *listview_create ( listview_update_callback cb, void *udata, unsigned i
* Navigation commands. * Navigation commands.
*/ */
void listview_nav_up ( listview *lv ) static void listview_nav_up_int ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv == NULL ) {
return; return;
@ -349,7 +416,7 @@ void listview_nav_up ( listview *lv )
lv->selected--; lv->selected--;
widget_queue_redraw ( WIDGET ( lv ) ); widget_queue_redraw ( WIDGET ( lv ) );
} }
void listview_nav_down ( listview *lv ) static void listview_nav_down_int ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv == NULL ) {
return; return;
@ -362,6 +429,23 @@ void listview_nav_down ( listview *lv )
widget_queue_redraw ( WIDGET ( lv ) ); widget_queue_redraw ( WIDGET ( lv ) );
} }
void listview_nav_up ( listview *lv )
{
if ( lv->reverse ) {
listview_nav_down_int ( lv );
} else {
listview_nav_up_int ( lv );
}
}
void listview_nav_down ( listview *lv )
{
if ( lv->reverse ) {
listview_nav_up_int ( lv );
} else {
listview_nav_down_int ( lv );
}
}
void listview_nav_left ( listview *lv ) void listview_nav_left ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv == NULL ) {
@ -396,7 +480,7 @@ void listview_nav_right ( listview *lv )
} }
} }
void listview_nav_page_prev ( listview *lv ) static void listview_nav_page_prev_int ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv == NULL ) {
return; return;
@ -409,7 +493,7 @@ void listview_nav_page_prev ( listview *lv )
} }
widget_queue_redraw ( WIDGET ( lv ) ); widget_queue_redraw ( WIDGET ( lv ) );
} }
void listview_nav_page_next ( listview *lv ) static void listview_nav_page_next_int ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv == NULL ) {
return; return;
@ -424,50 +508,51 @@ void listview_nav_page_next ( listview *lv )
widget_queue_redraw ( WIDGET ( lv ) ); widget_queue_redraw ( WIDGET ( lv ) );
} }
unsigned int listview_get_desired_height ( listview *lv ) void listview_nav_page_prev ( listview *lv )
{ {
if ( lv == NULL ) { if ( lv->reverse ){
listview_nav_page_next_int ( lv );
} else {
listview_nav_page_prev_int ( lv );
}
}
void listview_nav_page_next ( listview *lv )
{
if ( lv->reverse ){
listview_nav_page_prev_int ( lv );
} else {
listview_nav_page_next_int ( lv );
}
}
static int listview_get_desired_height ( widget *wid )
{
listview *lv = (listview *)wid;
int spacing = distance_get_pixel ( lv->spacing, ORIENTATION_VERTICAL );
if ( lv == NULL || lv->widget.enabled == FALSE ) {
return 0; return 0;
} }
int h = lv->menu_lines; int h = lv->menu_lines;
if ( !( lv->fixed_num_lines ) ) { if ( !( lv->fixed_num_lines ) ) {
if ( lv->dynamic ) {
h = MIN ( lv->menu_lines, lv->req_elements ); h = MIN ( lv->menu_lines, lv->req_elements );
} else {
h = MIN ( lv->menu_lines, lv->max_displayed_lines );
}
} }
if ( h == 0 ) { if ( h == 0 ) {
if ( lv->dynamic && !lv->fixed_num_lines ){
// Hide widget fully.
return 0; return 0;
} }
return h * lv->element_height + ( h - 1 ) * lv->padding; return widget_padding_get_padding_height ( WIDGET (lv) );
}
int height = widget_padding_get_padding_height ( WIDGET (lv) );
height += h*(lv->element_height+spacing) - spacing;
return height;
} }
/** void listview_set_show_scrollbar ( listview *lv, gboolean enabled )
* Configure the widget!
*/
void listview_set_padding ( listview *lv, unsigned int padding )
{
if ( lv ) {
lv->padding = padding;
}
}
void listview_set_max_lines ( listview *lv, unsigned int lines )
{
if ( lv ) {
lv->menu_lines = lines;
}
}
void listview_set_max_columns ( listview *lv, unsigned int columns )
{
if ( lv ) {
lv->menu_columns = columns;
}
}
void listview_set_fixed_num_lines ( listview *lv, gboolean enabled )
{
if ( lv ) {
lv->fixed_num_lines = enabled;
}
}
void listview_set_hide_scrollbar ( listview *lv, gboolean enabled )
{ {
if ( lv ) { if ( lv ) {
if ( enabled ) { if ( enabled ) {
@ -479,19 +564,7 @@ void listview_set_hide_scrollbar ( listview *lv, gboolean enabled )
listview_recompute_elements ( lv ); listview_recompute_elements ( lv );
} }
} }
void listview_set_scrollbar_width ( listview *lv, unsigned int width )
{
if ( lv ) {
widget_resize ( WIDGET ( lv->scrollbar ), width, widget_get_height ( WIDGET ( lv->scrollbar ) ) );
}
}
void listview_set_cycle ( listview *lv, gboolean cycle )
{
if ( lv ) {
lv->cycle = cycle;
}
}
void listview_set_scroll_type ( listview *lv, ScrollType type ) void listview_set_scroll_type ( listview *lv, ScrollType type )
{ {
if ( lv ) { if ( lv ) {
@ -512,3 +585,37 @@ void listview_set_multi_select ( listview *lv, gboolean enable )
lv->multi_select = enable; lv->multi_select = enable;
} }
} }
void listview_set_num_lines ( listview *lv, unsigned int num_lines )
{
if ( lv ) {
lv->menu_lines = num_lines;
}
}
unsigned int listview_get_num_lines ( listview *lv )
{
if ( lv ) {
return lv->menu_lines;
}
return 0;
}
void listview_set_max_lines ( listview *lv, unsigned int max_lines )
{
if ( lv ) {
lv->max_displayed_lines = max_lines;
}
}
gboolean listview_get_fixed_num_lines ( listview *lv )
{
if ( lv ) {
return lv->fixed_num_lines;
}
return FALSE;
}
void listview_set_fixed_num_lines ( listview *lv )
{
if ( lv ) {
lv->fixed_num_lines = TRUE;
}
}

View file

@ -27,24 +27,37 @@
#include <glib.h> #include <glib.h>
#include "widgets/scrollbar.h" #include "widgets/scrollbar.h"
#include "x11-helper.h" #include "x11-helper.h"
#include "settings.h"
#include "theme.h"
#define DEFAULT_SCROLLBAR_WIDTH 8
static void scrollbar_draw ( widget *, cairo_t * ); static void scrollbar_draw ( widget *, cairo_t * );
static void scrollbar_free ( widget * ); static void scrollbar_free ( widget * );
static gboolean scrollbar_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ); static gboolean scrollbar_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme );
scrollbar *scrollbar_create ( short x, short y, short w, short h )
static int scrollbar_get_desired_height ( widget *wid )
{
// Want height we are.
return wid->h;
}
scrollbar *scrollbar_create ( const char *name )
{ {
scrollbar *sb = g_malloc0 ( sizeof ( scrollbar ) ); scrollbar *sb = g_malloc0 ( sizeof ( scrollbar ) );
widget_init ( WIDGET (sb), name );
sb->widget.x = x; sb->widget.x = 0;
sb->widget.y = y; sb->widget.y = 0;
sb->widget.w = MAX ( 1, w ); sb->width = rofi_theme_get_distance ( WIDGET (sb), "handle-width", DEFAULT_SCROLLBAR_WIDTH );
sb->widget.h = MAX ( 1, h ); int width = distance_get_pixel (sb->width, ORIENTATION_HORIZONTAL);
sb->widget.w = widget_padding_get_padding_width ( WIDGET (sb)) + width;
sb->widget.h = widget_padding_get_padding_height ( WIDGET ( sb ) );
sb->widget.draw = scrollbar_draw; sb->widget.draw = scrollbar_draw;
sb->widget.free = scrollbar_free; sb->widget.free = scrollbar_free;
sb->widget.motion_notify = scrollbar_motion_notify; sb->widget.motion_notify = scrollbar_motion_notify;
sb->widget.get_desired_height = scrollbar_get_desired_height;
sb->length = 10; sb->length = 10;
sb->pos = 0; sb->pos = 0;
@ -97,20 +110,26 @@ void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length )
static void scrollbar_draw ( widget *wid, cairo_t *draw ) static void scrollbar_draw ( widget *wid, cairo_t *draw )
{ {
scrollbar *sb = (scrollbar *) wid; scrollbar *sb = (scrollbar *) wid;
unsigned int wh = widget_padding_get_remaining_height ( wid );
// Calculate position and size. // Calculate position and size.
unsigned int r = ( sb->length * wid->h ) / ( (double) ( sb->length + sb->pos_length ) ); unsigned int r = ( sb->length * wh ) / ( (double) ( sb->length + sb->pos_length ) );
unsigned int handle = wid->h - r; unsigned int handle = wid->h - r;
double sec = ( ( r ) / (double) ( sb->length - 1 ) ); double sec = ( ( r ) / (double) ( sb->length - 1 ) );
unsigned int height = handle; unsigned int height = handle;
unsigned int y = sb->pos * sec; unsigned int y = sb->pos * sec;
// Set max pos. // Set max pos.
y = MIN ( y, wid->h - handle ); y = MIN ( y, wh - handle );
// Never go out of bar. // Never go out of bar.
height = MAX ( 2, height ); height = MAX ( 2, height );
// Cap length; // Cap length;
color_separator ( draw ); rofi_theme_get_color ( WIDGET (sb ), "foreground", draw );
rofi_theme_get_color ( WIDGET (sb ), "handle-color", draw );
cairo_rectangle ( draw, sb->widget.x, sb->widget.y + y, sb->widget.w, height ); cairo_rectangle ( draw,
widget_padding_get_left ( wid ),
widget_padding_get_top ( wid ) + y,
widget_padding_get_remaining_width ( wid ),
height );
cairo_fill ( draw ); cairo_fill ( draw );
} }
static gboolean scrollbar_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme ) static gboolean scrollbar_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme )
@ -140,3 +159,4 @@ unsigned int scrollbar_clicked ( const scrollbar *sb, int y )
} }
return 0; return 0;
} }

View file

@ -1,129 +0,0 @@
/**
* MIT/X11 License
* Modified (c) 2016-2017 Qball Cow <qball@gmpclient.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <xkbcommon/xkbcommon.h>
#include <glib.h>
#include <string.h>
#include "widgets/widget.h"
#include "widgets/widget-internal.h"
#include "widgets/separator.h"
#include "x11-helper.h"
#include "settings.h"
/**
* Internal structure for the separator.
*/
struct _separator
{
widget widget;
separator_type type;
separator_line_style line_style;
};
/** Configuration value for separator style indicating no line */
const char *const _separator_style_none = "none";
/** Configuration value for separator style indicating dashed line. */
const char *const _separator_style_dash = "dash";
static void separator_draw ( widget *, cairo_t * );
static void separator_free ( widget * );
separator *separator_create ( separator_type type, short sw )
{
separator *sb = g_malloc0 ( sizeof ( separator ) );
sb->type = type;
sb->widget.x = 0;
sb->widget.y = 0;
if ( sb->type == S_HORIZONTAL ) {
sb->widget.w = 1;
sb->widget.h = MAX ( 1, sw );
}
else {
sb->widget.h = 1;
sb->widget.w = MAX ( 1, sw );
}
sb->widget.draw = separator_draw;
sb->widget.free = separator_free;
// Enabled by default
sb->widget.enabled = TRUE;
return sb;
}
static void separator_free ( widget *wid )
{
separator *sb = (separator *) wid;
g_free ( sb );
}
void separator_set_line_style ( separator *sp, separator_line_style style )
{
if ( sp ) {
sp->line_style = style;
widget_need_redraw ( WIDGET ( sp ) );
}
}
void separator_set_line_style_from_string ( separator *sp, const char *style_str )
{
if ( !sp ) {
return;
}
separator_line_style style = S_LINE_SOLID;
if ( g_strcmp0 ( style_str, _separator_style_none ) == 0 ) {
style = S_LINE_NONE;
}
else if ( g_strcmp0 ( style_str, _separator_style_dash ) == 0 ) {
style = S_LINE_DASH;
}
separator_set_line_style ( sp, style );
}
static void separator_draw ( widget *wid, cairo_t *draw )
{
separator *sep = (separator *) wid;
if ( sep->line_style == S_LINE_NONE ) {
// Nothing to draw.
return;
}
color_separator ( draw );
if ( sep->line_style == S_LINE_DASH ) {
const double dashes[1] = { 4 };
cairo_set_dash ( draw, dashes, 1, 0.0 );
}
if ( sep->type == S_HORIZONTAL ) {
cairo_set_line_width ( draw, wid->h );
double half = wid->h / 2.0;
cairo_move_to ( draw, wid->x, wid->y + half );
cairo_line_to ( draw, wid->x + wid->w, wid->y + half );
}
else {
cairo_set_line_width ( draw, wid->w );
double half = wid->w / 2.0;
cairo_move_to ( draw, wid->x + half, wid->y );
cairo_line_to ( draw, wid->x + half, wid->y + wid->h );
}
cairo_stroke ( draw );
}

View file

@ -29,19 +29,21 @@
#include <string.h> #include <string.h>
#include <glib.h> #include <glib.h>
#include <math.h> #include <math.h>
#include "settings.h"
#include "widgets/textbox.h" #include "widgets/textbox.h"
#include "keyb.h" #include "keyb.h"
#include "x11-helper.h" #include "x11-helper.h"
#include "mode.h" #include "mode.h"
#include "view.h" #include "view.h"
#include "theme.h"
#define DOT_OFFSET 15 #define DOT_OFFSET 15
static void textbox_draw ( widget *, cairo_t * ); static void textbox_draw ( widget *, cairo_t * );
static void textbox_free ( widget * ); static void textbox_free ( widget * );
static int textbox_get_width ( widget * ); static int textbox_get_width ( widget * );
static int _textbox_get_height ( widget * ); static int _textbox_get_height ( widget * );
static void __textbox_update_pango_text ( textbox *tb );
/** /**
* @param tb Handle to the textbox * @param tb Handle to the textbox
@ -50,26 +52,6 @@ static int _textbox_get_height ( widget * );
*/ */
static void textbox_cursor_end ( textbox *tb ); static void textbox_cursor_end ( textbox *tb );
/**
* Font + font color cache.
* Avoid re-loading font on every change on every textbox.
*/
typedef struct
{
Color fg;
Color bg;
Color bgalt;
Color hlfg;
Color hlbg;
} RowColor;
/** Number of states */
#define num_states 3
/**
* Different colors for the different states
*/
RowColor colors[num_states];
/** Default pango context */ /** Default pango context */
static PangoContext *p_context = NULL; static PangoContext *p_context = NULL;
/** The pango font metrics */ /** The pango font metrics */
@ -95,24 +77,34 @@ static void textbox_resize ( widget *wid, short w, short h )
textbox *tb = (textbox *) wid; textbox *tb = (textbox *) wid;
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, w, h ); textbox_moveresize ( tb, tb->widget.x, tb->widget.y, w, h );
} }
static int textbox_get_desired_height ( widget *wid )
{
textbox *tb = (textbox *)wid;
if ( (tb->flags & TB_AUTOHEIGHT) == 0 )
{
return tb->widget.h;
}
if ( tb->changed ) {
__textbox_update_pango_text ( tb );
}
int height = textbox_get_height (tb);
return height;
}
textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h, textbox* textbox_create ( const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text )
TextBoxFontType tbft, const char *text )
{ {
textbox *tb = g_slice_new0 ( textbox ); textbox *tb = g_slice_new0 ( textbox );
widget_init ( WIDGET (tb), name );
tb->widget.draw = textbox_draw; tb->widget.draw = textbox_draw;
tb->widget.free = textbox_free; tb->widget.free = textbox_free;
tb->widget.resize = textbox_resize; tb->widget.resize = textbox_resize;
tb->widget.get_width = textbox_get_width; tb->widget.get_width = textbox_get_width;
tb->widget.get_height = _textbox_get_height; tb->widget.get_height = _textbox_get_height;
tb->widget.get_desired_height = textbox_get_desired_height;
tb->flags = flags; tb->flags = flags;
tb->widget.x = x;
tb->widget.y = y;
tb->widget.w = MAX ( 1, w );
tb->widget.h = MAX ( 1, h );
tb->changed = FALSE; tb->changed = FALSE;
tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->widget.w, tb->widget.h ); tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->widget.w, tb->widget.h );
@ -140,6 +132,18 @@ textbox* textbox_create ( TextboxFlags flags, short x, short y, short w, short h
return tb; return tb;
} }
/**
* State names used for theming.
*/
const char const *const theme_prop_names[][3] = {
/** Normal row */
{"normal.normal", "selected.normal", "alternate.normal"},
/** Urgent row */
{"normal.urgent", "selected.urgent", "alternate.urgent"},
/** Active row */
{"normal.active", "selected.active", "alternate.active"},
};
void textbox_font ( textbox *tb, TextBoxFontType tbft ) void textbox_font ( textbox *tb, TextBoxFontType tbft )
{ {
TextBoxFontType t = tbft & STATE_MASK; TextBoxFontType t = tbft & STATE_MASK;
@ -150,23 +154,19 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft )
if ( t == ( URGENT | ACTIVE ) ) { if ( t == ( URGENT | ACTIVE ) ) {
t = ACTIVE; t = ACTIVE;
} }
RowColor *color = &( colors[t] );
switch ( ( tbft & FMOD_MASK ) ) switch ( ( tbft & FMOD_MASK ) )
{ {
case HIGHLIGHT: case HIGHLIGHT:
tb->color_bg = color->hlbg; widget_set_state ( WIDGET (tb), theme_prop_names[t][1]);
tb->color_fg = color->hlfg;
break; break;
case ALT: case ALT:
tb->color_bg = color->bgalt; widget_set_state ( WIDGET (tb), theme_prop_names[t][2]);
tb->color_fg = color->fg;
break; break;
default: default:
tb->color_bg = color->bg; widget_set_state ( WIDGET (tb), theme_prop_names[t][0]);
tb->color_fg = color->fg;
break; break;
} }
if ( tb->tbft != tbft ) { if ( tb->tbft != tbft || tb->widget.state == NULL ) {
tb->update = TRUE; tb->update = TRUE;
widget_queue_redraw ( WIDGET ( tb ) ); widget_queue_redraw ( WIDGET ( tb ) );
} }
@ -232,7 +232,9 @@ void textbox_text ( textbox *tb, const char *text )
__textbox_update_pango_text ( tb ); __textbox_update_pango_text ( tb );
if ( tb->flags & TB_AUTOWIDTH ) { if ( tb->flags & TB_AUTOWIDTH ) {
textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h ); textbox_moveresize ( tb, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
widget_update ( WIDGET ( tb ) ); if ( WIDGET(tb)->parent ){
widget_update ( WIDGET ( tb )->parent );
}
} }
tb->cursor = MAX ( 0, MIN ( ( int ) g_utf8_strlen ( tb->text, -1 ), tb->cursor ) ); tb->cursor = MAX ( 0, MIN ( ( int ) g_utf8_strlen ( tb->text, -1 ), tb->cursor ) );
@ -246,7 +248,7 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
if ( tb->flags & TB_AUTOWIDTH ) { if ( tb->flags & TB_AUTOWIDTH ) {
pango_layout_set_width ( tb->layout, -1 ); pango_layout_set_width ( tb->layout, -1 );
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
w = textbox_get_font_width ( tb ) + 2 * config.line_padding + offset; w = textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( WIDGET (tb) ) + offset;
} }
else { else {
// set ellipsize // set ellipsize
@ -261,8 +263,9 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
if ( tb->flags & TB_AUTOHEIGHT ) { if ( tb->flags & TB_AUTOHEIGHT ) {
// Width determines height! // Width determines height!
int tw = MAX ( 1, w ); int tw = MAX ( 1, w );
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tw - 2 * config.line_padding - offset ) ); pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tw - widget_padding_get_padding_width ( WIDGET (tb) ) - offset ) );
h = textbox_get_height ( tb ); int hd = textbox_get_height ( tb );
h = MAX (hd, h);
} }
if ( x != tb->widget.x || y != tb->widget.y || w != tb->widget.w || h != tb->widget.h ) { if ( x != tb->widget.x || y != tb->widget.y || w != tb->widget.w || h != tb->widget.h ) {
@ -273,7 +276,7 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
} }
// We always want to update this // We always want to update this
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->widget.w - 2 * config.line_padding - offset ) ); pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->widget.w - widget_padding_get_padding_width ( WIDGET (tb) ) - offset ) );
tb->update = TRUE; tb->update = TRUE;
widget_queue_redraw ( WIDGET ( tb ) ); widget_queue_redraw ( WIDGET ( tb ) );
} }
@ -286,7 +289,6 @@ static void textbox_free ( widget *wid )
g_source_remove ( tb->blink_timeout ); g_source_remove ( tb->blink_timeout );
tb->blink_timeout = 0; tb->blink_timeout = 0;
} }
g_free ( tb->text ); g_free ( tb->text );
if ( tb->layout != NULL ) { if ( tb->layout != NULL ) {
@ -316,13 +318,15 @@ static void texbox_update ( textbox *tb )
} }
tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->widget.w, tb->widget.h ); tb->main_surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, tb->widget.w, tb->widget.h );
tb->main_draw = cairo_create ( tb->main_surface ); tb->main_draw = cairo_create ( tb->main_surface );
cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_SOURCE ); cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_OVER );
pango_cairo_update_layout ( tb->main_draw, tb->layout ); pango_cairo_update_layout ( tb->main_draw, tb->layout );
int font_height = textbox_get_font_height ( tb ); int font_height = textbox_get_font_height ( tb );
int cursor_x = 0; int cursor_x = 0;
int cursor_width = MAX ( 2, font_height / 10 ); int cursor_y = 0;
int cursor_width = 2;//MAX ( 2, font_height / 10 );
int cursor_height = font_height;
if ( tb->changed ) { if ( tb->changed ) {
__textbox_update_pango_text ( tb ); __textbox_update_pango_text ( tb );
@ -338,50 +342,52 @@ static void texbox_update ( textbox *tb )
char *offset = g_utf8_offset_to_pointer ( text, cursor_offset ); char *offset = g_utf8_offset_to_pointer ( text, cursor_offset );
pango_layout_get_cursor_pos ( tb->layout, offset - text, &pos, NULL ); pango_layout_get_cursor_pos ( tb->layout, offset - text, &pos, NULL );
cursor_x = pos.x / PANGO_SCALE; cursor_x = pos.x / PANGO_SCALE;
cursor_y = pos.y / PANGO_SCALE;
cursor_height = pos.height/PANGO_SCALE;
} }
// Skip the side MARGIN on the X axis. // Skip the side MARGIN on the X axis.
int x = config.line_padding + offset; int x = widget_padding_get_left ( WIDGET (tb) ) + offset;
int y = 0; int y = 0;
if ( tb->flags & TB_RIGHT ) { if ( tb->flags & TB_RIGHT ) {
int line_width = 0; int line_width = 0;
// Get actual width. // Get actual width.
pango_layout_get_pixel_size ( tb->layout, &line_width, NULL ); pango_layout_get_pixel_size ( tb->layout, &line_width, NULL );
x = ( tb->widget.w - line_width - config.line_padding - offset ); x = ( tb->widget.w - line_width - widget_padding_get_right ( WIDGET (tb) ) - offset );
} }
else if ( tb->flags & TB_CENTER ) { else if ( tb->flags & TB_CENTER ) {
int tw = textbox_get_font_width ( tb ); int tw = textbox_get_font_width ( tb );
x = ( ( tb->widget.w - tw - 2 * config.line_padding - offset ) ) / 2; x = ( ( tb->widget.w - tw - widget_padding_get_padding_width( WIDGET (tb) ) - offset ) ) / 2;
} }
y = config.line_padding + ( pango_font_metrics_get_ascent ( p_metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE; y = widget_padding_get_top ( WIDGET (tb) ) + ( pango_font_metrics_get_ascent ( p_metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE;
// Set ARGB // Set background transparency
Color col = tb->color_bg; //cairo_set_source_rgba ( tb->main_draw, 0,0,0,0.0);
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha ); //cairo_paint ( tb->main_draw );
cairo_paint ( tb->main_draw );
col = tb->color_fg; rofi_theme_get_color ( WIDGET ( tb ), "foreground", tb->main_draw);
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
// draw the cursor // draw the cursor
if ( tb->flags & TB_EDITABLE && tb->blink ) { if ( tb->flags & TB_EDITABLE && tb->blink ) {
cairo_rectangle ( tb->main_draw, x + cursor_x, y, cursor_width, font_height ); cairo_rectangle ( tb->main_draw, x + cursor_x, y+cursor_y, cursor_width, cursor_height);
cairo_fill ( tb->main_draw ); cairo_fill ( tb->main_draw );
} }
// Set ARGB // Set ARGB
// We need to set over, otherwise subpixel hinting wont work. // We need to set over, otherwise subpixel hinting wont work.
cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_OVER ); //cairo_set_operator ( tb->main_draw, CAIRO_OPERATOR_OVER );
cairo_move_to ( tb->main_draw, x, y ); cairo_move_to ( tb->main_draw, x, y );
pango_cairo_show_layout ( tb->main_draw, tb->layout ); pango_cairo_show_layout ( tb->main_draw, tb->layout );
if ( ( tb->flags & TB_INDICATOR ) == TB_INDICATOR && ( tb->tbft & ( SELECTED | HIGHLIGHT ) ) ) { if ( ( tb->flags & TB_INDICATOR ) == TB_INDICATOR && ( tb->tbft & ( SELECTED ) ) ) {
/*
if ( ( tb->tbft & SELECTED ) == SELECTED ) { if ( ( tb->tbft & SELECTED ) == SELECTED ) {
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha ); cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
} }
else if ( ( tb->tbft & HIGHLIGHT ) == HIGHLIGHT ) { else if ( ( tb->tbft & HIGHLIGHT ) == HIGHLIGHT ) {
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha * 0.2 ); cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha * 0.2 );
} }
*/
cairo_arc ( tb->main_draw, DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * M_PI ); cairo_arc ( tb->main_draw, DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * M_PI );
cairo_fill ( tb->main_draw ); cairo_fill ( tb->main_draw );
@ -396,9 +402,8 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
texbox_update ( tb ); texbox_update ( tb );
/* Write buffer */ /* Write buffer */
cairo_set_source_surface ( draw, tb->main_surface, 0,0 );
cairo_set_source_surface ( draw, tb->main_surface, tb->widget.x, tb->widget.y ); cairo_rectangle ( draw, 0,0, tb->widget.w, tb->widget.h );
cairo_rectangle ( draw, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
cairo_fill ( draw ); cairo_fill ( draw );
} }
@ -709,47 +714,8 @@ gboolean textbox_append_char ( textbox *tb, const char *pad, const int pad_len )
return FALSE; return FALSE;
} }
/***
* Font setup.
*/
static void textbox_parse_string ( const char *str, RowColor *color )
{
if ( str == NULL ) {
return;
}
char *cstr = g_strdup ( str );
char *endp = NULL;
char *token;
int index = 0;
const char *const sep = ",";
for ( token = strtok_r ( cstr, sep, &endp ); token != NULL; token = strtok_r ( NULL, sep, &endp ) ) {
switch ( index )
{
case 0:
color->bg = color_get ( g_strstrip ( token ) );
break;
case 1:
color->fg = color_get ( g_strstrip ( token ) );
break;
case 2:
color->bgalt = color_get ( g_strstrip ( token ) );
break;
case 3:
color->hlbg = color_get ( g_strstrip ( token ) );
break;
case 4:
color->hlfg = color_get ( g_strstrip ( token ) );
break;
}
index++;
}
g_free ( cstr );
}
void textbox_setup ( void ) void textbox_setup ( void )
{ {
textbox_parse_string ( config.color_normal, &( colors[NORMAL] ) );
textbox_parse_string ( config.color_urgent, &( colors[URGENT] ) );
textbox_parse_string ( config.color_active, &( colors[ACTIVE] ) );
} }
void textbox_set_pango_context ( PangoContext *p ) void textbox_set_pango_context ( PangoContext *p )
@ -774,12 +740,9 @@ void textbox_cleanup ( void )
int textbox_get_width ( widget *wid ) int textbox_get_width ( widget *wid )
{ {
textbox *tb = (textbox *) wid; textbox *tb = (textbox *) wid;
if ( !wid->expand ) {
if ( tb->flags & TB_AUTOWIDTH ) { if ( tb->flags & TB_AUTOWIDTH ) {
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
return textbox_get_font_width ( tb ) + 2 * config.line_padding + offset; return textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( wid ) + offset;
}
return tb->widget.w;
} }
return tb->widget.w; return tb->widget.w;
} }
@ -787,17 +750,14 @@ int textbox_get_width ( widget *wid )
int _textbox_get_height ( widget *wid ) int _textbox_get_height ( widget *wid )
{ {
textbox *tb = (textbox *) wid; textbox *tb = (textbox *) wid;
if ( !wid->expand ) {
if ( tb->flags & TB_AUTOHEIGHT ) { if ( tb->flags & TB_AUTOHEIGHT ) {
return textbox_get_height ( tb ); return textbox_get_height ( tb );
} }
return tb->widget.h; return tb->widget.h;
}
return tb->widget.h;
} }
int textbox_get_height ( const textbox *tb ) int textbox_get_height ( const textbox *tb )
{ {
return textbox_get_font_height ( tb ) + 2 * config.line_padding; return textbox_get_font_height ( tb ) + widget_padding_get_padding_height ( WIDGET (tb) );
} }
int textbox_get_font_height ( const textbox *tb ) int textbox_get_font_height ( const textbox *tb )
@ -814,14 +774,30 @@ int textbox_get_font_width ( const textbox *tb )
return width; return width;
} }
double textbox_get_estimated_char_width ( void ) /** Caching for the expected character height. */
static double char_height = -1;
double textbox_get_estimated_char_height ( void )
{ {
int width = pango_font_metrics_get_approximate_char_width ( p_metrics ); if ( char_height < 0 ){
return ( width ) / (double) PANGO_SCALE; int height = pango_font_metrics_get_ascent ( p_metrics ) + pango_font_metrics_get_descent ( p_metrics );
char_height = ( height ) / (double) PANGO_SCALE;
}
return char_height;
} }
int textbox_get_estimated_char_height ( void ) /** Caching for the expected character width. */
static double char_width = -1;
double textbox_get_estimated_char_width ( void )
{
if ( char_width < 0 ){
int width = pango_font_metrics_get_approximate_char_width ( p_metrics );
char_width = ( width ) / (double) PANGO_SCALE;
}
return char_width;
}
int textbox_get_estimated_height ( const textbox *tb, int eh )
{ {
int height = pango_font_metrics_get_ascent ( p_metrics ) + pango_font_metrics_get_descent ( p_metrics ); int height = pango_font_metrics_get_ascent ( p_metrics ) + pango_font_metrics_get_descent ( p_metrics );
return ( height ) / PANGO_SCALE + 2 * config.line_padding; return ( eh*height ) / PANGO_SCALE + widget_padding_get_padding_height ( WIDGET ( tb ) );
} }

View file

@ -1,6 +1,31 @@
#include <glib.h> #include <glib.h>
#include "widgets/widget.h" #include "widgets/widget.h"
#include "widgets/widget-internal.h" #include "widgets/widget-internal.h"
#include "theme.h"
void widget_init ( widget *widget , const char *name )
{
widget->name = g_strdup(name);
widget->padding = (Padding){ {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}};
widget->border = (Padding){ {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}};
widget->margin = (Padding){ {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}, {0, PW_PX, SOLID}};
widget->padding = rofi_theme_get_padding ( widget, "padding", widget->padding);
widget->border = rofi_theme_get_padding ( widget, "border", widget->border);
widget->margin = rofi_theme_get_padding ( widget, "margin", widget->margin);
}
void widget_set_state ( widget *widget, const char *state )
{
if ( g_strcmp0(widget->state, state ) ){
widget->state = state;
// Update border.
widget->border = rofi_theme_get_padding ( widget, "border", widget->border);
widget_queue_redraw ( widget );
}
}
int widget_intersect ( const widget *widget, int x, int y ) int widget_intersect ( const widget *widget, int x, int y )
{ {
@ -20,12 +45,16 @@ void widget_resize ( widget *widget, short w, short h )
{ {
if ( widget != NULL ) { if ( widget != NULL ) {
if ( widget->resize != NULL ) { if ( widget->resize != NULL ) {
if ( widget->w != w || widget->h != h ) {
widget->resize ( widget, w, h ); widget->resize ( widget, w, h );
} }
}
else { else {
widget->w = w; widget->w = w;
widget->h = h; widget->h = h;
} }
// On a resize we always want to udpate.
widget_queue_redraw ( widget );
} }
} }
void widget_move ( widget *widget, short x, short y ) void widget_move ( widget *widget, short x, short y )
@ -49,6 +78,7 @@ void widget_enable ( widget *widget )
if ( widget && !widget->enabled ) { if ( widget && !widget->enabled ) {
widget->enabled = TRUE; widget->enabled = TRUE;
widget_update ( widget ); widget_update ( widget );
widget_update ( widget->parent );
} }
} }
void widget_disable ( widget *widget ) void widget_disable ( widget *widget )
@ -56,21 +86,92 @@ void widget_disable ( widget *widget )
if ( widget && widget->enabled ) { if ( widget && widget->enabled ) {
widget->enabled = FALSE; widget->enabled = FALSE;
widget_update ( widget ); widget_update ( widget );
widget_update ( widget->parent );
} }
} }
void widget_draw ( widget *widget, cairo_t *d ) void widget_draw ( widget *widget, cairo_t *d )
{ {
// Check if enabled and if draw is implemented. // Check if enabled and if draw is implemented.
if ( widget && widget->enabled && widget->draw ) { if ( widget && widget->enabled && widget->draw ) {
// Don't draw if there is no space.
if ( widget->h < 1 || widget->w < 1 ){
widget->need_redraw = FALSE;
return;
}
// Store current state.
cairo_save ( d );
int margin_left = distance_get_pixel ( widget->margin.left, ORIENTATION_HORIZONTAL);
int margin_top = distance_get_pixel ( widget->margin.top, ORIENTATION_VERTICAL);
int margin_right = distance_get_pixel ( widget->margin.right, ORIENTATION_HORIZONTAL);
int margin_bottom = distance_get_pixel ( widget->margin.bottom, ORIENTATION_VERTICAL);
// Define a clipmask so we won't draw outside out widget.
cairo_rectangle ( d,
widget->x+margin_left,
widget->y+margin_top,
widget->w-margin_right-margin_left,
widget->h-margin_top-margin_bottom
);
cairo_clip ( d );
rofi_theme_get_color ( widget, "background", d );
cairo_paint( d ) ;
// Set new x/y possition.
cairo_translate ( d, widget->x, widget->y);
int left = distance_get_pixel ( widget->border.left, ORIENTATION_HORIZONTAL );
int right = distance_get_pixel ( widget->border.right, ORIENTATION_HORIZONTAL);
int top = distance_get_pixel ( widget->border.top, ORIENTATION_VERTICAL);
int bottom = distance_get_pixel ( widget->border.bottom, ORIENTATION_VERTICAL );
if ( left || top || right || bottom ) {
cairo_save ( d );
rofi_theme_get_color ( widget, "foreground", d );
if ( left > 0 ) {
cairo_set_line_width ( d, left );
distance_get_linestyle ( widget->border.left, d);
cairo_move_to ( d, margin_left + left/2.0, margin_top );
cairo_line_to ( d, margin_left + left/2.0, widget->h-margin_bottom);
cairo_stroke ( d );
}
if ( right > 0 ) {
cairo_set_line_width ( d, right );
distance_get_linestyle ( widget->border.right, d);
cairo_move_to ( d, widget->w - margin_right - right/2.0, 0 );
cairo_line_to ( d, widget->w - margin_right - right/2.0, widget->h-margin_bottom );
cairo_stroke ( d );
}
if ( top > 0 ) {
cairo_set_line_width ( d, top );
distance_get_linestyle ( widget->border.top, d);
cairo_move_to ( d, margin_left,margin_top+ top/2.0 );
cairo_line_to ( d, widget->w-margin_right, margin_top+top/2.0 );
cairo_stroke ( d );
}
if ( bottom > 0 ) {
cairo_set_line_width ( d, bottom );
distance_get_linestyle ( widget->border.bottom, d);
cairo_move_to ( d, margin_left, widget->h-bottom/2.0-margin_bottom);
cairo_line_to ( d, widget->w-margin_right, widget->h-bottom/2.0-margin_bottom);
cairo_stroke ( d );
}
cairo_restore (d);
}
widget->draw ( widget, d ); widget->draw ( widget, d );
widget->need_redraw = FALSE; widget->need_redraw = FALSE;
cairo_restore ( d );
} }
} }
void widget_free ( widget *wid ) void widget_free ( widget *wid )
{ {
if ( wid && wid->free ) { if ( wid ) {
if ( wid->name ) {
g_free ( wid->name );
}
if ( wid->free ) {
wid->free ( wid ); wid->free ( wid );
} }
}
} }
int widget_get_height ( widget *widget ) int widget_get_height ( widget *widget )
@ -115,8 +216,6 @@ void widget_update ( widget *widget )
if ( widget->update ) { if ( widget->update ) {
widget->update ( widget ); widget->update ( widget );
} }
// Recurse back.
widget_update ( widget->parent );
} }
} }
@ -163,3 +262,79 @@ gboolean widget_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme )
return FALSE; return FALSE;
} }
void widget_set_name ( widget *wid, const char *name )
{
if ( wid->name ) {
g_free(wid);
}
wid->name = g_strdup ( name );
}
int widget_padding_get_left ( const widget *wid )
{
int distance = distance_get_pixel ( wid->padding.left, ORIENTATION_HORIZONTAL );
distance += distance_get_pixel ( wid->border.left, ORIENTATION_HORIZONTAL );
distance += distance_get_pixel ( wid->margin.left, ORIENTATION_HORIZONTAL );
return distance;
}
int widget_padding_get_right ( const widget *wid )
{
int distance = distance_get_pixel ( wid->padding.right, ORIENTATION_HORIZONTAL );
distance += distance_get_pixel ( wid->border.right, ORIENTATION_HORIZONTAL );
distance += distance_get_pixel ( wid->margin.right, ORIENTATION_HORIZONTAL );
return distance;
}
int widget_padding_get_top ( const widget *wid )
{
int distance = distance_get_pixel ( wid->padding.top, ORIENTATION_VERTICAL );
distance += distance_get_pixel ( wid->border.top, ORIENTATION_VERTICAL );
distance += distance_get_pixel ( wid->margin.top, ORIENTATION_VERTICAL );
return distance;
}
int widget_padding_get_bottom ( const widget *wid )
{
int distance = distance_get_pixel ( wid->padding.bottom, ORIENTATION_VERTICAL );
distance += distance_get_pixel ( wid->border.bottom, ORIENTATION_VERTICAL );
distance += distance_get_pixel ( wid->margin.bottom, ORIENTATION_VERTICAL );
return distance;
}
int widget_padding_get_remaining_width ( const widget *wid )
{
int width = wid->w;
width -= widget_padding_get_left ( wid );
width -= widget_padding_get_right ( wid );
return width;
}
int widget_padding_get_remaining_height ( const widget *wid )
{
int height = wid->h;
height -= widget_padding_get_top ( wid );
height -= widget_padding_get_bottom ( wid );
return height;
}
int widget_padding_get_padding_height ( const widget *wid )
{
int height = 0;
height += widget_padding_get_top ( wid );
height += widget_padding_get_bottom ( wid );
return height;
}
int widget_padding_get_padding_width ( const widget *wid )
{
int width = 0;
width += widget_padding_get_left ( wid );
width += widget_padding_get_right ( wid );
return width;
}
int widget_get_desired_height ( widget *wid )
{
if ( wid && wid->get_desired_height )
{
return wid->get_desired_height ( wid );
}
return 0;
}

View file

@ -194,6 +194,8 @@ static XrmOption xrmOptions[] = {
"Click outside the window to exit", CONFIG_DEFAULT }, "Click outside the window to exit", CONFIG_DEFAULT },
{ xrm_Boolean, "show-match", { .snum = &config.show_match }, NULL, { xrm_Boolean, "show-match", { .snum = &config.show_match }, NULL,
"Indicate how it match by underlining it.", CONFIG_DEFAULT }, "Indicate how it match by underlining it.", CONFIG_DEFAULT },
{ xrm_String, "theme", { .str = &config.theme }, NULL,
"New style theme file", CONFIG_DEFAULT },
}; };
/** Dynamic array of extra options */ /** Dynamic array of extra options */

View file

@ -22,6 +22,16 @@ unsigned int test =0;
abort ( ); \ abort ( ); \
} \ } \
} }
int textbox_get_estimated_char_height ( void );
int textbox_get_estimated_char_height ( void )
{
return 16;
}
void rofi_view_get_current_monitor ( int *width, int *height )
{
}
static gboolean test_widget_clicked ( G_GNUC_UNUSED widget *wid, G_GNUC_UNUSED xcb_button_press_event_t* xce, G_GNUC_UNUSED void *data ) static gboolean test_widget_clicked ( G_GNUC_UNUSED widget *wid, G_GNUC_UNUSED xcb_button_press_event_t* xce, G_GNUC_UNUSED void *data )
{ {
@ -31,11 +41,12 @@ static gboolean test_widget_clicked ( G_GNUC_UNUSED widget *wid, G_GNUC_UNUSED x
int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv ) int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
{ {
{ {
box *b = box_create ( BOX_HORIZONTAL, 0, 0, 100, 20 ); box *b = box_create ( "box", BOX_HORIZONTAL );
box_set_padding ( b, 5 ); //box_set_padding ( b, 5 );
widget_resize ( WIDGET (b), 100, 20);
widget *wid1 = g_malloc0(sizeof(widget)); widget *wid1 = g_malloc0(sizeof(widget));
box_add ( b , WIDGET( wid1 ), TRUE, FALSE ); box_add ( b , WIDGET( wid1 ), TRUE, 0 );
// Widget not enabled. no width allocated. // Widget not enabled. no width allocated.
TASSERTE ( wid1->h, 0); TASSERTE ( wid1->h, 0);
TASSERTE ( wid1->w, 0 ); TASSERTE ( wid1->w, 0 );
@ -46,57 +57,58 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
TASSERTE ( wid1->w, 100 ); TASSERTE ( wid1->w, 100 );
widget *wid2 = g_malloc0(sizeof(widget)); widget *wid2 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid2 ) ); widget_enable ( WIDGET ( wid2 ) );
box_add ( b , WIDGET( wid2 ), TRUE, FALSE ); box_add ( b , WIDGET( wid2 ), TRUE, 1 );
TASSERTE ( wid1->h, 20); TASSERTE ( wid1->h, 20);
TASSERTE ( wid1->w, 47); TASSERTE ( wid1->w, 49);
TASSERTE ( wid2->h, 20); TASSERTE ( wid2->h, 20);
TASSERTE ( wid2->w, 48); TASSERTE ( wid2->w, 49);
widget *wid3 = g_malloc0(sizeof(widget)); widget *wid3 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid3 ) ); widget_enable ( WIDGET ( wid3 ) );
box_add ( b , WIDGET( wid3 ), FALSE, FALSE ); box_add ( b , WIDGET( wid3 ), FALSE, 2 );
TASSERTE ( wid1->h, 20); TASSERTE ( wid1->h, 20);
TASSERTE ( wid1->w, 45); TASSERTE ( wid1->w, 48);
TASSERTE ( wid2->h, 20); TASSERTE ( wid2->h, 20);
TASSERTE ( wid2->w, 45); TASSERTE ( wid2->w, 48);
widget_resize ( WIDGET (wid3) , 20, 10 ); widget_resize ( WIDGET (wid3) , 20, 10 );
// TODO should this happen automagically? // TODO should this happen automagically?
widget_update ( WIDGET ( b ) ) ; widget_update ( WIDGET ( b ) ) ;
TASSERTE ( wid1->h, 20); TASSERTE ( wid1->h, 20);
TASSERTE ( wid1->w, 35); TASSERTE ( wid1->w, 38);
TASSERTE ( wid2->h, 20); TASSERTE ( wid2->h, 20);
TASSERTE ( wid2->w, 35); TASSERTE ( wid2->w, 38);
TASSERTE ( wid3->h, 20); TASSERTE ( wid3->h, 20);
TASSERTE ( wid3->w, 20); TASSERTE ( wid3->w, 20);
widget_resize ( WIDGET (b ), 200, 20 ); widget_resize ( WIDGET (b ), 200, 20 );
TASSERTE ( wid1->h, 20); TASSERTE ( wid1->h, 20);
TASSERTE ( wid1->w, 85); TASSERTE ( wid1->w, 88);
TASSERTE ( wid2->h, 20); TASSERTE ( wid2->h, 20);
TASSERTE ( wid2->w, 85); TASSERTE ( wid2->w, 88);
TASSERTE ( wid3->h, 20); TASSERTE ( wid3->h, 20);
TASSERTE ( wid3->w, 20); TASSERTE ( wid3->w, 20);
TASSERTE ( box_get_fixed_pixels ( b ) , 30 ); TASSERTE ( box_get_fixed_pixels ( b ) , 24 );
widget *wid4 = g_malloc0(sizeof(widget)); widget *wid4 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid4 ) ); widget_enable ( WIDGET ( wid4 ) );
widget_resize ( WIDGET ( wid4 ), 20, 20 ); widget_resize ( WIDGET ( wid4 ), 20, 20 );
box_add ( b , WIDGET( wid4 ), FALSE, TRUE ); box_add ( b , WIDGET( wid4 ), FALSE, 5 );
TASSERTE ( wid4->x, 200-20); TASSERTE ( wid4->x, 200-20);
widget *wid5 = g_malloc0(sizeof(widget)); widget *wid5 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid5 ) ); widget_enable ( WIDGET ( wid5 ) );
widget_resize ( WIDGET ( wid5 ), 20, 20 ); widget_resize ( WIDGET ( wid5 ), 20, 20 );
box_add ( b , WIDGET( wid5 ), TRUE, TRUE ); box_add ( b , WIDGET( wid5 ), TRUE, 6 );
TASSERTE ( wid5->x, 128); TASSERTE ( wid5->x, 149);
widget_free ( WIDGET ( b ) ); widget_free ( WIDGET ( b ) );
} }
{ {
box *b = box_create ( BOX_VERTICAL, 0, 0, 20, 100 ); box *b = box_create ( "box", BOX_VERTICAL );
box_set_padding ( b, 5 ); widget_resize ( WIDGET (b), 20, 100);
//box_set_padding ( b, 5 );
widget *wid1 = g_malloc0(sizeof(widget)); widget *wid1 = g_malloc0(sizeof(widget));
box_add ( b , WIDGET( wid1 ), TRUE, FALSE ); box_add ( b , WIDGET( wid1 ), TRUE, 0 );
// Widget not enabled. no width allocated. // Widget not enabled. no width allocated.
TASSERTE ( wid1->h, 0); TASSERTE ( wid1->h, 0);
TASSERTE ( wid1->w, 0 ); TASSERTE ( wid1->w, 0 );
@ -107,60 +119,62 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
TASSERTE ( wid1->w, 20 ); TASSERTE ( wid1->w, 20 );
widget *wid2 = g_malloc0(sizeof(widget)); widget *wid2 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid2 ) ); widget_enable ( WIDGET ( wid2 ) );
box_add ( b , WIDGET( wid2 ), TRUE, FALSE ); box_add ( b , WIDGET( wid2 ), TRUE, 1 );
TASSERTE ( wid1->w, 20); TASSERTE ( wid1->w, 20);
TASSERTE ( wid1->h, 47); TASSERTE ( wid1->h, 49);
TASSERTE ( wid2->w, 20); TASSERTE ( wid2->w, 20);
TASSERTE ( wid2->h, 48); TASSERTE ( wid2->h, 49);
widget *wid3 = g_malloc0(sizeof(widget)); widget *wid3 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid3 ) ); widget_enable ( WIDGET ( wid3 ) );
box_add ( b , WIDGET( wid3 ), FALSE, FALSE ); box_add ( b , WIDGET( wid3 ), FALSE, 2 );
TASSERTE ( wid1->w, 20); TASSERTE ( wid1->w, 20);
TASSERTE ( wid1->h, 45); TASSERTE ( wid1->h, 48);
TASSERTE ( wid2->w, 20); TASSERTE ( wid2->w, 20);
TASSERTE ( wid2->h, 45); TASSERTE ( wid2->h, 48);
widget_resize ( WIDGET (wid3) , 10, 20 ); widget_resize ( WIDGET (wid3) , 10, 20 );
// TODO should this happen automagically? // TODO should this happen automagically?
widget_update ( WIDGET ( b ) ) ; widget_update ( WIDGET ( b ) ) ;
TASSERTE ( wid1->w, 20); TASSERTE ( wid1->w, 20);
TASSERTE ( wid1->h, 35); TASSERTE ( wid1->h, 48);
TASSERTE ( wid2->w, 20); TASSERTE ( wid2->w, 20);
TASSERTE ( wid2->h, 35); TASSERTE ( wid2->h, 48);
TASSERTE ( wid3->w, 20); TASSERTE ( wid3->w, 20);
TASSERTE ( wid3->h, 20); TASSERTE ( wid3->h, 0);
widget_resize ( WIDGET (b ), 20, 200 ); widget_resize ( WIDGET (b ), 20, 200 );
TASSERTE ( wid1->w, 20); TASSERTE ( wid1->w, 20);
TASSERTE ( wid1->h, 85); TASSERTE ( wid1->h, 98);
TASSERTE ( wid2->w, 20); TASSERTE ( wid2->w, 20);
TASSERTE ( wid2->h, 85); TASSERTE ( wid2->h, 98);
TASSERTE ( wid3->w, 20); TASSERTE ( wid3->w, 20);
TASSERTE ( wid3->h, 20); // has no height, gets no height.
TASSERTE ( box_get_fixed_pixels ( b ) , 30 ); TASSERTE ( wid3->h, 0);
TASSERTE ( box_get_fixed_pixels ( b ) , 4 );
widget *wid4 = g_malloc0(sizeof(widget)); widget *wid4 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid4 ) ); widget_enable ( WIDGET ( wid4 ) );
widget_resize ( WIDGET ( wid4 ), 20, 20 ); widget_resize ( WIDGET ( wid4 ), 20, 20 );
box_add ( b , WIDGET( wid4 ), FALSE, TRUE ); box_add ( b , WIDGET( wid4 ), FALSE, 5 );
TASSERTE ( wid4->y, 200-20); TASSERTE ( wid4->y, 200);
widget *wid5 = g_malloc0(sizeof(widget)); widget *wid5 = g_malloc0(sizeof(widget));
widget_enable ( WIDGET ( wid5 ) ); widget_enable ( WIDGET ( wid5 ) );
widget_resize ( WIDGET ( wid5 ), 20, 20 ); widget_resize ( WIDGET ( wid5 ), 20, 20 );
box_add ( b , WIDGET( wid5 ), TRUE, TRUE ); box_add ( b , WIDGET( wid5 ), TRUE, 6 );
TASSERTE ( wid5->y, 128); TASSERTE ( wid5->y, 136);
widget_free ( WIDGET ( b ) ); widget_free ( WIDGET ( b ) );
} }
{ {
box *b = box_create ( BOX_VERTICAL, 0, 0, 20, 100 ); box *b = box_create ( "box", BOX_VERTICAL );
box_set_padding ( b, 5 ); widget_resize ( WIDGET (b), 20, 100);
//box_set_padding ( b, 5 );
widget *wid1 = g_malloc0(sizeof(widget)); widget *wid1 = g_malloc0(sizeof(widget));
widget_enable(wid1); widget_enable(wid1);
wid1->clicked = test_widget_clicked; wid1->clicked = test_widget_clicked;
box_add ( b , WIDGET( wid1 ), TRUE, FALSE ); box_add ( b , WIDGET( wid1 ), TRUE, 0 );
widget *wid2 = g_malloc0(sizeof(widget)); widget *wid2 = g_malloc0(sizeof(widget));
widget_enable(wid2); widget_enable(wid2);
box_add ( b , WIDGET( wid2 ), TRUE, FALSE ); box_add ( b , WIDGET( wid2 ), TRUE, 1 );
xcb_button_press_event_t xce; xcb_button_press_event_t xce;
xce.event_x = 10; xce.event_x = 10;
@ -169,7 +183,7 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
xce.event_y = 50; xce.event_y = 50;
TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 0); TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 0);
xce.event_y = 45; xce.event_y = 48;
TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 1); TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 1);
widget_disable ( wid2 ); widget_disable ( wid2 );
xce.event_y = 60; xce.event_y = 60;

View file

@ -23,14 +23,25 @@ unsigned int test =0;
} \ } \
} }
int textbox_get_estimated_char_height ( void );
int textbox_get_estimated_char_height ( void )
{
return 16;
}
void color_separator ( G_GNUC_UNUSED void *d ) void color_separator ( G_GNUC_UNUSED void *d )
{ {
} }
void rofi_view_get_current_monitor ( int *width, int *height )
{
}
int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv ) int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
{ {
scrollbar * sb = scrollbar_create ( 0, 0, 10, 100); scrollbar * sb = scrollbar_create ( "scrollbar" );
widget_resize ( WIDGET (sb), 10, 100);
scrollbar_set_handle ( NULL, 10213); scrollbar_set_handle ( NULL, 10213);
scrollbar_set_max_value ( NULL, 10 ); scrollbar_set_max_value ( NULL, 10 );

View file

@ -24,12 +24,10 @@ unsigned int normal_window_mode = 0;
void rofi_view_queue_redraw () void rofi_view_queue_redraw ()
{ {
} }
Color color_get ( G_GNUC_UNUSED const char *name ) void rofi_view_get_current_monitor ( int *width, int *height )
{ {
Color retv = { 1.0, 1.0, 1.0, 1.0 };
return retv;
}
}
int rofi_view_error_dialog ( const char *msg, G_GNUC_UNUSED int markup ) int rofi_view_error_dialog ( const char *msg, G_GNUC_UNUSED int markup )
{ {
fputs ( msg, stderr ); fputs ( msg, stderr );
@ -53,8 +51,7 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
PangoContext *p = pango_cairo_create_context ( draw ); PangoContext *p = pango_cairo_create_context ( draw );
textbox_set_pango_context ( p ); textbox_set_pango_context ( p );
textbox *box = textbox_create ( TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, 0, 0, -1, -1, textbox *box = textbox_create ( "textbox", TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "test" );
NORMAL, "test" );
TASSERT ( box != NULL ); TASSERT ( box != NULL );
textbox_keybinding ( box, MOVE_END ); textbox_keybinding ( box, MOVE_END );

View file

@ -12,7 +12,19 @@ unsigned int test =0;
assert ( a ); \ assert ( a ); \
printf ( "Test %3i passed (%s)\n", ++test, # a ); \ printf ( "Test %3i passed (%s)\n", ++test, # a ); \
} }
void rofi_view_queue_redraw ( void )
{
}
void rofi_view_get_current_monitor ( int *width, int *height )
{
}
int rofi_view_error_dialog ( const char *msg, G_GNUC_UNUSED int markup )
{
fputs ( msg, stderr );
return FALSE;
}
int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv ) int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
{ {

View file

@ -4,11 +4,11 @@
! Copyright: Dave Davenport ! Copyright: Dave Davenport
! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------
! "Color scheme for normal row" Set from: File ! "Color scheme for normal row" Set from: File
rofi.color-normal: argb:0000000, #dbdfbc, argb:00000000, #dbdfbc, #02143f rofi.color-normal: argb:00000000, #dbdfbc, argb:00000000, #dbdfbc, #02143f
! "Color scheme for urgent row" Set from: File ! "Color scheme for urgent row" Set from: File
rofi.color-urgent: argb:0000000, #ff81ff, argb:00000000, #ff817f, #02143f rofi.color-urgent: argb:00000000, #ff81ff, argb:00000000, #ff817f, #02143f
! "Color scheme for active row" Set from: File ! "Color scheme for active row" Set from: File
rofi.color-active: argb:0000000, #8ac4ff, argb:00000000, #8ac4ff, #02143f rofi.color-active: argb:00000000, #8ac4ff, argb:00000000, #8ac4ff, #02143f
! "Color scheme window" Set from: File ! "Color scheme window" Set from: File
rofi.color-window: argb:dd000021, #dbdfbc, #dbdfbc rofi.color-window: argb:dd000021, #dbdfbc, #dbdfbc
! "Separator style (none, dash, solid)" Set from: XResources ! "Separator style (none, dash, solid)" Set from: XResources