mirror of
https://github.com/lbonn/rofi
synced 2024-11-27 14:21:07 +00:00
commit
8fe5ea648a
41 changed files with 3353 additions and 784 deletions
|
@ -4,7 +4,7 @@ before_script:
|
|||
- add-apt-repository -y 'deb http://debian.jpleau.ca/ jessie-backports main contrib non-free'
|
||||
- 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 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
|
||||
- cd xcb-util-xrm
|
||||
- ./autogen.sh --prefix=/usr
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
* autoconf
|
||||
* automake (1.11.3 or up)
|
||||
* pkg-config
|
||||
* flex
|
||||
* bison
|
||||
* Developer packages of the external libraries
|
||||
|
||||
### External libraries
|
||||
|
|
40
Makefile.am
40
Makefile.am
|
@ -3,9 +3,18 @@ AUTOMAKE_OPTIONS = 1.11.3
|
|||
|
||||
ACLOCAL_AMFLAGS = -I libgwater ${ACLOCAL_FLAGS}
|
||||
|
||||
AM_YFLAGS = -d
|
||||
|
||||
noinst_LIBRARIES =
|
||||
include $(top_srcdir)/libgwater-xcb-nolibtool.mk
|
||||
|
||||
|
||||
BUILT_SOURCES=\
|
||||
lexer/theme-parser.h\
|
||||
lexer/theme-parser.c\
|
||||
lexer/theme-lexer.c
|
||||
|
||||
|
||||
##
|
||||
# Rofi the program
|
||||
##
|
||||
|
@ -27,12 +36,13 @@ rofi_SOURCES=\
|
|||
source/helper.c\
|
||||
source/timings.c\
|
||||
source/history.c\
|
||||
source/theme.c\
|
||||
source/widgets/box.c\
|
||||
source/widgets/container.c\
|
||||
source/widgets/widget.c\
|
||||
source/widgets/textbox.c\
|
||||
source/widgets/listview.c\
|
||||
source/widgets/scrollbar.c\
|
||||
source/widgets/separator.c\
|
||||
source/xrmoptions.c\
|
||||
source/x11-helper.c\
|
||||
source/dialogs/run.c\
|
||||
|
@ -43,6 +53,8 @@ rofi_SOURCES=\
|
|||
source/dialogs/window.c\
|
||||
source/dialogs/script.c\
|
||||
source/dialogs/help-keys.c\
|
||||
lexer/theme-parser.y\
|
||||
lexer/theme-lexer.l\
|
||||
include/xcb.h\
|
||||
include/xcb-internal.h\
|
||||
include/rofi.h\
|
||||
|
@ -55,13 +67,14 @@ rofi_SOURCES=\
|
|||
include/helper.h\
|
||||
include/timings.h\
|
||||
include/history.h\
|
||||
include/theme.h\
|
||||
include/widgets/box.h\
|
||||
include/widgets/container.h\
|
||||
include/widgets/widget.h\
|
||||
include/widgets/widget-internal.h\
|
||||
include/widgets/textbox.h\
|
||||
include/widgets/listview.h\
|
||||
include/widgets/scrollbar.h\
|
||||
include/widgets/separator.h\
|
||||
include/xrmoptions.h\
|
||||
include/x11-helper.h\
|
||||
include/dialogs/ssh.h\
|
||||
|
@ -88,7 +101,8 @@ rofi_CFLAGS=\
|
|||
-I$(top_srcdir)/config/\
|
||||
-I$(top_builddir)/\
|
||||
-Werror=missing-prototypes\
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\"\
|
||||
-DTHEME_CONVERTER
|
||||
|
||||
rofi_LDADD=\
|
||||
$(glib_LIBS)\
|
||||
|
@ -259,6 +273,13 @@ widget_test_LDADD=$(textbox_test_LDADD)
|
|||
widget_test_CFLAGS=$(textbox_test_CFLAGS)
|
||||
widget_test_SOURCES=\
|
||||
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
|
||||
|
||||
box_test_LDADD=$(textbox_test_LDADD)
|
||||
|
@ -266,6 +287,10 @@ box_test_CFLAGS=$(textbox_test_CFLAGS)
|
|||
box_test_SOURCES=\
|
||||
source/widgets/widget.c\
|
||||
source/widgets/box.c\
|
||||
lexer/theme-parser.y\
|
||||
lexer/theme-lexer.l\
|
||||
source/theme.c\
|
||||
include/theme.h\
|
||||
test/box-test.c
|
||||
|
||||
scrollbar_test_LDADD=$(textbox_test_LDADD)
|
||||
|
@ -273,11 +298,20 @@ scrollbar_test_CFLAGS=$(textbox_test_CFLAGS)
|
|||
scrollbar_test_SOURCES=\
|
||||
source/widgets/widget.c\
|
||||
source/widgets/scrollbar.c\
|
||||
lexer/theme-parser.y\
|
||||
lexer/theme-lexer.l\
|
||||
source/theme.c\
|
||||
include/theme.h\
|
||||
test/scrollbar-test.c
|
||||
|
||||
textbox_test_SOURCES=\
|
||||
source/widgets/widget.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\
|
||||
include/keyb.h\
|
||||
include/rofi.h\
|
||||
|
|
|
@ -128,4 +128,5 @@ Settings config = {
|
|||
.window_format = "{w} {c} {t}",
|
||||
.click_to_exit = TRUE,
|
||||
.show_match = TRUE,
|
||||
.theme = NULL,
|
||||
};
|
||||
|
|
|
@ -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_HEADER([config.h])
|
||||
|
||||
|
||||
AC_PROG_LEX
|
||||
AC_PROG_YACC
|
||||
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Setup automake to be silent and in foreign mode.
|
||||
dnl We want xz distribution
|
||||
|
|
|
@ -135,6 +135,8 @@ Global options:
|
|||
True (Default)
|
||||
-[no-]show-match Indicate how it match by underlining it.
|
||||
True (Default)
|
||||
-theme [string] New style theme file
|
||||
(unset) (Default)
|
||||
-pid [string] Pidfile location
|
||||
/tmp/rofi.pid (File)
|
||||
-kb-primary-paste [string] Paste primary selection
|
||||
|
|
|
@ -98,6 +98,8 @@ rofi.window-format: w c t
|
|||
! rofi.click-to-exit: true
|
||||
! "Indicate how it match by underlining it." Set from: Default
|
||||
! rofi.show-match: true
|
||||
! "New style theme file" Set from: Default
|
||||
! rofi.theme:
|
||||
! "Pidfile location" Set from: File
|
||||
rofi.pid: /tmp/rofi.pid
|
||||
! "Paste primary selection" Set from: File
|
||||
|
|
172
doc/themer.md
Normal file
172
doc/themer.md
Normal 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.
|
||||
|
|
@ -82,6 +82,14 @@ int find_arg_int ( const char * const key, int *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
|
||||
*
|
||||
|
|
|
@ -38,7 +38,7 @@ typedef enum
|
|||
/** Middle right */
|
||||
WL_EAST = 4,
|
||||
/** Bottom right */
|
||||
WL_EAST_SOUTH = 5,
|
||||
WL_SOUTH_EAST = 5,
|
||||
/** Bottom middle */
|
||||
WL_SOUTH = 6,
|
||||
/** Bottom left */
|
||||
|
@ -149,6 +149,8 @@ typedef struct
|
|||
/** Click outside the window to exit */
|
||||
int click_to_exit;
|
||||
gboolean show_match;
|
||||
|
||||
char *theme;
|
||||
} Settings;
|
||||
/** Global Settings structure. */
|
||||
extern Settings config;
|
||||
|
|
337
include/theme.h
Normal file
337
include/theme.h
Normal 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
|
|
@ -1,12 +1,13 @@
|
|||
#ifndef ROFI_VIEW_INTERNAL_H
|
||||
#define ROFI_VIEW_INTERNAL_H
|
||||
#include "widgets/container.h"
|
||||
#include "widgets/widget.h"
|
||||
#include "widgets/textbox.h"
|
||||
#include "widgets/separator.h"
|
||||
#include "widgets/listview.h"
|
||||
#include "widgets/box.h"
|
||||
#include "keyb.h"
|
||||
#include "x11-helper.h"
|
||||
#include "theme.h"
|
||||
|
||||
/**
|
||||
* @ingroup ViewHandle
|
||||
|
@ -22,7 +23,8 @@ struct RofiViewState
|
|||
|
||||
/** Flag indicating if view needs to be refiltered. */
|
||||
int refilter;
|
||||
|
||||
/** Widget representing the main container. */
|
||||
container *main_window;
|
||||
/** Main #box widget holding different elements. */
|
||||
box *main_box;
|
||||
/** #box widget packing the input bar widgets. */
|
||||
|
@ -33,8 +35,6 @@ struct RofiViewState
|
|||
textbox *text;
|
||||
/** #textbox showing the state of the case sensitive and sortng. */
|
||||
textbox *case_indicator;
|
||||
/** #separator widget below the input bar. */
|
||||
separator *input_bar_separator;
|
||||
|
||||
/** #listview holding the displayed elements. */
|
||||
listview *list_view;
|
||||
|
@ -63,8 +63,6 @@ struct RofiViewState
|
|||
unsigned int selected_line;
|
||||
/** The return state of the view */
|
||||
MenuReturn retv;
|
||||
/** Calculated border width */
|
||||
unsigned int border;
|
||||
/** Monitor #workarea the view is displayed on */
|
||||
workarea mon;
|
||||
|
||||
|
|
|
@ -111,12 +111,6 @@ unsigned int rofi_view_get_selected_line ( const 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
|
||||
|
@ -254,5 +248,12 @@ void rofi_view_workers_initialize ( void );
|
|||
* Stop all threads and free the resources used by the threadpool
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -32,42 +32,31 @@ typedef enum
|
|||
} boxType;
|
||||
|
||||
/**
|
||||
* @param name The name of the widget.
|
||||
* @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
|
||||
*/
|
||||
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 child Handle to the child widget to pack.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
|
|
34
include/widgets/container.h
Normal file
34
include/widgets/container.h
Normal 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
|
|
@ -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 * );
|
||||
|
||||
/**
|
||||
* @param name The name of the to be created widget.
|
||||
* @param cb The update callback.
|
||||
* @param udata The user data to pass to the callback
|
||||
* @param eh The height of one element
|
||||
* @param reverse Reverse the listview order.
|
||||
*
|
||||
* @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
|
||||
|
@ -75,15 +77,6 @@ void listview_set_selected ( listview *lv, unsigned int selected );
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
@ -131,44 +124,13 @@ void listview_nav_page_next ( 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 enabled enable
|
||||
*
|
||||
* 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 width Width in pixels
|
||||
|
@ -207,6 +169,47 @@ void listview_set_mouse_activated_cb ( listview *lv, listview_mouse_activated_cb
|
|||
* Enable,disable multi-select.
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -19,19 +19,17 @@ typedef struct _scrollbar
|
|||
unsigned int length;
|
||||
unsigned int pos;
|
||||
unsigned int pos_length;
|
||||
Distance width;
|
||||
} scrollbar;
|
||||
|
||||
/**
|
||||
* @param x The x coordinate (relative to parent) to position the new scrollbar
|
||||
* @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
|
||||
* @param name The name of the widget.
|
||||
*
|
||||
* Create a new scrollbar
|
||||
*
|
||||
* @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
|
||||
|
|
|
@ -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
|
|
@ -39,6 +39,8 @@ typedef struct
|
|||
int update;
|
||||
int blink;
|
||||
guint blink_timeout;
|
||||
//
|
||||
const char *theme_name ;
|
||||
} textbox;
|
||||
|
||||
/**
|
||||
|
@ -84,11 +86,8 @@ typedef enum
|
|||
} TextBoxFontType;
|
||||
|
||||
/**
|
||||
* @param name The name of the to be created widget.
|
||||
* @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 text intial text to display.
|
||||
*
|
||||
|
@ -97,8 +96,7 @@ typedef enum
|
|||
* free with #widget_free
|
||||
* @returns a new #textbox
|
||||
*/
|
||||
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 );
|
||||
/**
|
||||
|
@ -200,6 +198,13 @@ int textbox_get_font_width ( const textbox *tb );
|
|||
*/
|
||||
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 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
|
||||
*/
|
||||
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.
|
||||
* This includes padding.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef WIDGET_INTERNAL_H
|
||||
#define WIDGET_INTERNAL_H
|
||||
|
||||
#include "theme.h"
|
||||
/**
|
||||
* Data structure holding the internal state of the Widget
|
||||
*/
|
||||
|
@ -14,10 +15,17 @@ struct _widget
|
|||
short w;
|
||||
/** Height of the widget */
|
||||
short h;
|
||||
/** Padding */
|
||||
Padding margin;
|
||||
Padding padding;
|
||||
Padding border;
|
||||
|
||||
/** enabled or not */
|
||||
gboolean enabled;
|
||||
/** Expand the widget when packed */
|
||||
gboolean expand;
|
||||
/*** The packing index */
|
||||
int index;
|
||||
/** Place widget at end of parent */
|
||||
gboolean end;
|
||||
/** Parent widget */
|
||||
|
@ -38,6 +46,8 @@ struct _widget
|
|||
/** Handle mouse motion, used for dragging */
|
||||
gboolean ( *motion_notify )( struct _widget *, xcb_motion_notify_event_t * );
|
||||
|
||||
int (*get_desired_height) ( struct _widget * );
|
||||
|
||||
/** widget clicked callback */
|
||||
widget_clicked_cb clicked;
|
||||
/** user data for clicked callback */
|
||||
|
@ -45,5 +55,95 @@ struct _widget
|
|||
|
||||
/** Free widget callback */
|
||||
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
|
||||
|
|
|
@ -173,5 +173,24 @@ void widget_set_clicked_handler ( widget *wid, widget_clicked_cb cb, void *udata
|
|||
* returns TRUE when handled.
|
||||
*/
|
||||
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
|
||||
|
|
336
lexer/theme-lexer.l
Normal file
336
lexer/theme-lexer.l
Normal 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
185
lexer/theme-parser.y
Normal 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
76
script/rofi-convert-theme.sh
Executable 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
|
|
@ -295,6 +295,27 @@ int find_arg_str ( const char * const key, char** val )
|
|||
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 i = find_arg ( key );
|
||||
|
|
|
@ -64,6 +64,8 @@
|
|||
|
||||
#include "gitconfig.h"
|
||||
|
||||
#include "theme.h"
|
||||
|
||||
// Pidfile.
|
||||
char *pidfile = 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 );
|
||||
--error_trap_depth;
|
||||
}
|
||||
|
||||
/** Retry count of grabbing keyboard. */
|
||||
unsigned int lazy_grab_retry_count_kb = 0;
|
||||
/** Retry count of grabbing pointer. */
|
||||
unsigned int lazy_grab_retry_count_pt = 0;
|
||||
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.
|
||||
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.
|
||||
// catch help request
|
||||
if ( find_arg ( "-h" ) >= 0 || find_arg ( "-help" ) >= 0 || find_arg ( "--help" ) >= 0 ) {
|
||||
|
|
840
source/theme.c
Normal file
840
source/theme.c
Normal 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
|
370
source/view.c
370
source/view.c
|
@ -58,10 +58,19 @@
|
|||
#include "view.h"
|
||||
#include "view-internal.h"
|
||||
|
||||
#include "theme.h"
|
||||
|
||||
/** The Rofi View log domain */
|
||||
#define LOG_DOMAIN "View"
|
||||
|
||||
#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 );
|
||||
|
||||
|
@ -99,9 +108,11 @@ struct
|
|||
/** timeout for reloading */
|
||||
guint idle_timeout;
|
||||
/** debug counter for redraws */
|
||||
uint64_t count;
|
||||
unsigned long long count;
|
||||
/** redraw idle time. */
|
||||
guint repaint_source;
|
||||
/** Window fullscreen */
|
||||
gboolean fullscreen;
|
||||
} CacheState = {
|
||||
.main_window = XCB_WINDOW_NONE,
|
||||
.fake_bg = NULL,
|
||||
|
@ -113,8 +124,18 @@ struct
|
|||
.idle_timeout = 0,
|
||||
.count = 0L,
|
||||
.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 )
|
||||
{
|
||||
if ( config.case_sensitive ) {
|
||||
|
@ -200,6 +221,10 @@ static void menu_capture_screenshot ( void )
|
|||
static gboolean rofi_view_repaint ( G_GNUC_UNUSED void * data )
|
||||
{
|
||||
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" );
|
||||
TICK_N ( "Expose" );
|
||||
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 )
|
||||
{
|
||||
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->y = CacheState.mon.y;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !config.fixed_num_lines && ( config.location == WL_CENTER || config.location == WL_EAST || config.location == WL_WEST ) ) {
|
||||
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;
|
||||
state->y = CacheState.mon.y + ( CacheState.mon.h ) / 2;
|
||||
state->x = CacheState.mon.x + ( CacheState.mon.w ) / 2;
|
||||
// Determine window location
|
||||
switch ( config.location )
|
||||
switch ( location )
|
||||
{
|
||||
case WL_NORTH_WEST:
|
||||
state->x = CacheState.mon.x;
|
||||
|
@ -256,15 +288,15 @@ static void rofi_view_calculate_window_position ( RofiViewState *state )
|
|||
case WL_NORTH_EAST:
|
||||
state->y = CacheState.mon.y;
|
||||
case WL_EAST:
|
||||
state->x = CacheState.mon.x + CacheState.mon.w - state->width;
|
||||
state->x = CacheState.mon.x + CacheState.mon.w;
|
||||
break;
|
||||
case WL_EAST_SOUTH:
|
||||
state->x = CacheState.mon.x + CacheState.mon.w - state->width;
|
||||
case WL_SOUTH_EAST:
|
||||
state->x = CacheState.mon.x + CacheState.mon.w;
|
||||
case WL_SOUTH:
|
||||
state->y = CacheState.mon.y + CacheState.mon.h - state->height;
|
||||
state->y = CacheState.mon.y + CacheState.mon.h;
|
||||
break;
|
||||
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:
|
||||
state->x = CacheState.mon.x;
|
||||
break;
|
||||
|
@ -272,6 +304,41 @@ static void rofi_view_calculate_window_position ( RofiViewState *state )
|
|||
default:
|
||||
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.
|
||||
state->x += config.x_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_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 )
|
||||
|
@ -319,7 +389,7 @@ void rofi_view_queue_redraw ( void )
|
|||
{
|
||||
if ( current_active_menu && CacheState.repaint_source == 0 ) {
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +452,7 @@ void rofi_view_free ( RofiViewState *state )
|
|||
}
|
||||
// Do this here?
|
||||
// Wait for final release?
|
||||
widget_free ( WIDGET ( state->main_box ) );
|
||||
widget_free ( WIDGET ( state->main_window ) );
|
||||
widget_free ( WIDGET ( state->overlay ) );
|
||||
|
||||
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 ) {
|
||||
cairo_surface_t *s = NULL;
|
||||
/**
|
||||
* Select Background to use for fake transparency.
|
||||
* Current options: 'screenshot','background'
|
||||
* Current options: 'real', 'screenshot','background'
|
||||
*/
|
||||
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 ();
|
||||
}
|
||||
else if ( g_strcmp0 ( config.fake_background, "background" ) == 0 ) {
|
||||
else if ( g_strcmp0 ( fake_background, "background" ) == 0 ) {
|
||||
s = x11_helper_get_bg_surface ();
|
||||
}
|
||||
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 );
|
||||
s = cairo_image_surface_create_from_png ( fpath );
|
||||
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 );
|
||||
}
|
||||
// Setup font.
|
||||
if ( config.menu_font ) {
|
||||
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
||||
// Dummy widget.
|
||||
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_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 );
|
||||
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->ewmh._NET_WM_STATE_FULLSCREEN,
|
||||
xcb->ewmh._NET_WM_STATE_ABOVE
|
||||
|
@ -620,12 +698,18 @@ void __create_window ( MenuFlags menu_flags )
|
|||
CacheState.main_window = box;
|
||||
CacheState.flags = menu_flags;
|
||||
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 ) {
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
return;
|
||||
}
|
||||
else if ( config.menu_width < 0 ) {
|
||||
if ( config.menu_width < 0 ) {
|
||||
double fw = textbox_get_estimated_char_width ( );
|
||||
state->width = -( fw * config.menu_width );
|
||||
state->width += 2 * state->border;
|
||||
state->width += widget_padding_get_padding_width ( WIDGET ( state->main_window ) );
|
||||
}
|
||||
else{
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
g_log ( LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Redraw view" );
|
||||
TICK ();
|
||||
cairo_t *d = CacheState.edit_draw;
|
||||
cairo_set_operator ( d, CAIRO_OPERATOR_SOURCE );
|
||||
if ( config.fake_transparency && CacheState.fake_bg != NULL ) {
|
||||
if ( CacheState.fake_bg != NULL ) {
|
||||
if ( CacheState.fake_bgrel ) {
|
||||
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_set_operator ( d, CAIRO_OPERATOR_OVER );
|
||||
color_background ( d );
|
||||
cairo_paint ( d );
|
||||
}
|
||||
else {
|
||||
// Paint the background.
|
||||
color_background ( d );
|
||||
// Paint the background transparent.
|
||||
cairo_set_source_rgba ( d, 0,0,0,0.0);
|
||||
cairo_paint ( d );
|
||||
}
|
||||
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.
|
||||
cairo_set_operator ( d, CAIRO_OPERATOR_OVER );
|
||||
widget_draw ( WIDGET ( state->main_box ), d );
|
||||
widget_draw ( WIDGET ( state->main_window ), d );
|
||||
|
||||
if ( state->overlay ) {
|
||||
widget_draw ( WIDGET ( state->overlay ), d );
|
||||
}
|
||||
TICK_N ( "widgets" );
|
||||
cairo_surface_flush ( CacheState.edit_surf );
|
||||
rofi_view_queue_redraw ();
|
||||
if ( qr ) {
|
||||
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' ) {
|
||||
unsigned int dl = strlen ( text );
|
||||
// Strip new line
|
||||
while ( dl > 0 && text[dl] == '\n' ) {
|
||||
text[dl] = '\0';
|
||||
dl--;
|
||||
for ( unsigned int i = 0; i < dl; i++){
|
||||
if ( text[i] == '\n' ){
|
||||
dl = i;
|
||||
}
|
||||
}
|
||||
// Insert string move cursor.
|
||||
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 {
|
||||
xcb_button_press_event_t rel = *xbe;
|
||||
rel.event_x -= config.padding;
|
||||
rel.event_y -= config.padding;
|
||||
if ( widget_clicked ( WIDGET ( state->main_box ), &rel ) ) {
|
||||
if ( widget_clicked ( WIDGET ( state->main_window ), &rel ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -879,6 +954,7 @@ static void _rofi_view_reload_row ( RofiViewState *state )
|
|||
state->num_lines = mode_get_num_entries ( state->sw );
|
||||
state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned 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 )
|
||||
|
@ -962,7 +1038,9 @@ static void rofi_view_refilter ( RofiViewState *state )
|
|||
state->retv = MENU_OK;
|
||||
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 );
|
||||
if ( height != state->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 ) {
|
||||
state->x = xce->x;
|
||||
state->y = xce->y;
|
||||
widget_queue_redraw ( WIDGET ( state->main_window ) );
|
||||
}
|
||||
if ( state->width != xce->width || state->height != xce->height ) {
|
||||
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_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;
|
||||
|
@ -1280,9 +1360,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
|
|||
state->mouse_seen = TRUE;
|
||||
}
|
||||
xcb_motion_notify_event_t xme = *( (xcb_motion_notify_event_t *) ev );
|
||||
xme.event_x -= config.padding;
|
||||
xme.event_y -= config.padding;
|
||||
if ( widget_motion_notify ( WIDGET ( state->main_box ), &xme ) ) {
|
||||
if ( widget_motion_notify ( WIDGET ( state->main_window ), &xme ) ) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -1340,7 +1418,7 @@ void rofi_view_itterrate ( RofiViewState *state, xcb_generic_event_t *ev, xkb_st
|
|||
if ( state->refilter ) {
|
||||
rofi_view_refilter ( state );
|
||||
}
|
||||
rofi_view_update ( state );
|
||||
rofi_view_update ( state, TRUE );
|
||||
|
||||
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 );
|
||||
|
@ -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 )
|
||||
{
|
||||
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;
|
||||
return height;
|
||||
}
|
||||
if ( state->filtered_lines == 0 && !config.fixed_num_lines ) {
|
||||
widget_disable ( WIDGET ( state->input_bar_separator ) );
|
||||
}
|
||||
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;
|
||||
|
||||
widget *main_window = WIDGET ( state->main_window );
|
||||
height = widget_get_desired_height ( main_window );
|
||||
return height;
|
||||
}
|
||||
|
||||
|
@ -1411,7 +1483,6 @@ RofiViewState *rofi_view_create ( Mode *sw,
|
|||
state->skip_absorb = FALSE;
|
||||
//We want to filter on the first run.
|
||||
state->refilter = TRUE;
|
||||
state->border = config.padding + config.menu_bw;
|
||||
state->finalize = finalize;
|
||||
state->mouse_seen = FALSE;
|
||||
|
||||
|
@ -1423,115 +1494,91 @@ RofiViewState *rofi_view_create ( Mode *sw,
|
|||
// Get active monitor size.
|
||||
TICK_N ( "Get active monitor" );
|
||||
|
||||
state->main_box = box_create ( BOX_VERTICAL,
|
||||
state->border, state->border,
|
||||
state->width - 2 * state->border, state->height - 2 * state->border );
|
||||
box_set_padding ( state->main_box, config.line_margin );
|
||||
state->main_window = container_create ( "window" );
|
||||
state->main_box = box_create ( "window.mainbox.box", BOX_VERTICAL );
|
||||
container_add ( state->main_window, WIDGET ( state->main_box ) );
|
||||
|
||||
// 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.
|
||||
if ( config.sidebar_mode ) {
|
||||
state->sidebar_bar = box_create ( BOX_HORIZONTAL, 0, 0, state->width - 2 * state->border, line_height );
|
||||
box_set_padding ( state->sidebar_bar, config.line_margin );
|
||||
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->sidebar_bar = box_create ( "window.mainbox.sidebar.box", BOX_HORIZONTAL );
|
||||
box_add ( state->main_box, WIDGET ( state->sidebar_bar ), FALSE, 10 );
|
||||
state->num_modi = rofi_get_num_enabled_modi ();
|
||||
state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) );
|
||||
for ( unsigned int j = 0; j < state->num_modi; 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 ) );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
int end = ( config.location == WL_EAST_SOUTH || config.location == WL_SOUTH || config.location == WL_SOUTH_WEST );
|
||||
box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end );
|
||||
int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location );
|
||||
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.
|
||||
box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, TRUE );
|
||||
box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, 3 );
|
||||
|
||||
// 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 );
|
||||
box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, FALSE );
|
||||
box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, 1 );
|
||||
|
||||
// Entry box
|
||||
TextboxFlags tfl = TB_EDITABLE;
|
||||
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 () );
|
||||
if ( message ) {
|
||||
textbox *message_tb = textbox_create ( TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, 0, 0,
|
||||
state->width - ( 2 * ( state->border ) ), -1, NORMAL, message );
|
||||
separator *sep = separator_create ( S_HORIZONTAL, 2 );
|
||||
box_add ( state->main_box, WIDGET ( sep ), FALSE, end);
|
||||
box_add ( state->main_box, WIDGET ( message_tb ), FALSE, end);
|
||||
separator_set_line_style_from_string ( sep, config.separator_style );
|
||||
container *box = container_create ( "window.mainbox.message.box" );
|
||||
textbox *message_tb = textbox_create ( "window.mainbox.message.textbox", TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, message );
|
||||
container_add ( box, WIDGET (message_tb) );
|
||||
box_add ( state->main_box, WIDGET ( box ), FALSE, end?8:2);
|
||||
}
|
||||
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 ) );
|
||||
|
||||
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
|
||||
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_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 );
|
||||
|
||||
|
||||
// Height of a row.
|
||||
if ( config.menu_lines == 0 || config.fullscreen ) {
|
||||
state->height = CacheState.mon.h;
|
||||
// Autosize it.
|
||||
config.fixed_num_lines = TRUE;
|
||||
}
|
||||
box_add ( state->main_box, WIDGET ( state->list_view ), TRUE, 3);
|
||||
|
||||
// filtered list
|
||||
state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned 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.
|
||||
rofi_view_calculate_window_position ( state );
|
||||
|
||||
rofi_view_window_update_size ( state );
|
||||
// Update.
|
||||
//state->selected = 0;
|
||||
|
||||
state->quit = FALSE;
|
||||
rofi_view_refilter ( state );
|
||||
|
||||
rofi_view_update ( state );
|
||||
rofi_view_update ( state, TRUE );
|
||||
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 );
|
||||
if ( xcb->sncontext != NULL ) {
|
||||
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 ();
|
||||
state->retv = MENU_CANCEL;
|
||||
state->border = config.padding + config.menu_bw;
|
||||
state->menu_flags = MENU_ERROR_DIALOG;
|
||||
state->finalize = process_result;
|
||||
|
||||
rofi_view_calculate_window_and_element_width ( state );
|
||||
state->main_box = box_create ( BOX_VERTICAL,
|
||||
state->border, state->border,
|
||||
state->width - 2 * state->border, state->height - 2 * state->border );
|
||||
state->text = textbox_create ( ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ),
|
||||
( state->border ), ( state->border ),
|
||||
( 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 );
|
||||
state->main_window = container_create ( "window" );
|
||||
state->main_box = box_create ( "window.mainbox.message.box", BOX_VERTICAL);
|
||||
container_add ( state->main_window, WIDGET ( state->main_box ) );
|
||||
state->text = textbox_create ( "window.mainbox.message.textbox", ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ),
|
||||
NORMAL, ( msg != NULL ) ? msg : "" );
|
||||
box_add ( state->main_box, WIDGET ( state->text ), TRUE, 1 );
|
||||
|
||||
|
||||
// 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
|
||||
state->height = line_height + ( state->border ) * 2;
|
||||
state->height = line_height + widget_padding_get_padding_height ( WIDGET(state->main_window) );
|
||||
|
||||
// Calculte window position.
|
||||
rofi_view_calculate_window_position ( state );
|
||||
|
@ -1568,7 +1620,7 @@ int rofi_view_error_dialog ( const char *msg, int markup )
|
|||
|
||||
// Display it.
|
||||
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 ) {
|
||||
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 ) );
|
||||
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 ) );
|
||||
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.
|
||||
rofi_view_queue_redraw ( );
|
||||
}
|
||||
|
@ -1707,7 +1767,7 @@ void rofi_view_switch_mode ( RofiViewState *state, Mode *mode )
|
|||
state->reload = TRUE;
|
||||
state->refilter = TRUE;
|
||||
rofi_view_refilter ( state );
|
||||
rofi_view_update ( state );
|
||||
rofi_view_update ( state, TRUE );
|
||||
}
|
||||
|
||||
xcb_window_t rofi_view_get_window ( void )
|
||||
|
|
|
@ -29,26 +29,75 @@
|
|||
#include "widgets/widget.h"
|
||||
#include "widgets/widget-internal.h"
|
||||
#include "widgets/box.h"
|
||||
#include "theme.h"
|
||||
|
||||
#define LOG_DOMAIN "Widgets.Box"
|
||||
|
||||
/** Default spacing used in the box*/
|
||||
#define DEFAULT_SPACING 2
|
||||
|
||||
struct _box
|
||||
{
|
||||
widget widget;
|
||||
boxType type;
|
||||
int max_size;
|
||||
// Padding between elements
|
||||
int padding;
|
||||
Distance spacing;
|
||||
|
||||
GList *children;
|
||||
};
|
||||
|
||||
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 )
|
||||
{
|
||||
int spacing = distance_get_pixel ( b->spacing, ORIENTATION_VERTICAL );
|
||||
int expanding_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;
|
||||
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||
widget * child = (widget *) iter->data;
|
||||
|
@ -60,17 +109,21 @@ static void vert_calculate_size ( box *b )
|
|||
expanding_widgets++;
|
||||
continue;
|
||||
}
|
||||
b->max_size += child->h;
|
||||
if ( child->h > 0 ){
|
||||
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 );
|
||||
return;
|
||||
}
|
||||
if ( active_widgets > 0 ) {
|
||||
int bottom = b->widget.h;
|
||||
int top = 0;
|
||||
double rem = b->widget.h - b->max_size;
|
||||
int top = widget_padding_get_top ( WIDGET ( b ) );
|
||||
double rem = rem_height - b->max_size;
|
||||
int index = 0;
|
||||
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||
widget * child = (widget *) iter->data;
|
||||
|
@ -80,40 +133,35 @@ static void vert_calculate_size ( box *b )
|
|||
if ( child->expand == TRUE ) {
|
||||
// Re-calculate to avoid round issues leaving one pixel left.
|
||||
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
|
||||
if ( child->end ) {
|
||||
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;
|
||||
widget_resize ( child, b->widget.w, expanding_widgets_size );
|
||||
top += b->padding;
|
||||
}
|
||||
widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
|
||||
top += expanding_widgets_size;
|
||||
widget_resize ( child, rem_width, expanding_widgets_size );
|
||||
top += spacing;
|
||||
rem -= expanding_widgets_size;
|
||||
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 {
|
||||
widget_move ( child, child->x, top );
|
||||
widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
|
||||
top += widget_get_height ( child );
|
||||
widget_resize ( child, b->widget.w, child->h );
|
||||
top += b->padding;
|
||||
top += spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
b->max_size += widget_padding_get_padding_height ( WIDGET (b) );
|
||||
}
|
||||
static void hori_calculate_size ( box *b )
|
||||
{
|
||||
int spacing = distance_get_pixel ( b->spacing, ORIENTATION_HORIZONTAL );
|
||||
int expanding_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;
|
||||
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||
widget * child = (widget *) iter->data;
|
||||
|
@ -126,17 +174,19 @@ static void hori_calculate_size ( box *b )
|
|||
continue;
|
||||
}
|
||||
// Size used by fixed width widgets.
|
||||
if ( child->h > 0 ){
|
||||
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 );
|
||||
return;
|
||||
}
|
||||
if ( active_widgets > 0 ) {
|
||||
int right = b->widget.w;
|
||||
int left = 0;
|
||||
double rem = b->widget.w - b->max_size;
|
||||
int left = widget_padding_get_left ( WIDGET (b) );
|
||||
double rem = rem_width - b->max_size;
|
||||
int index = 0;
|
||||
for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
|
||||
widget * child = (widget *) iter->data;
|
||||
|
@ -146,52 +196,30 @@ static void hori_calculate_size ( box *b )
|
|||
if ( child->expand == TRUE ) {
|
||||
// Re-calculate to avoid round issues leaving one pixel left.
|
||||
int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
|
||||
if ( child->end ) {
|
||||
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;
|
||||
widget_resize ( child, expanding_widgets_size, b->widget.h );
|
||||
left += b->padding;
|
||||
}
|
||||
widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
|
||||
left += expanding_widgets_size;
|
||||
widget_resize ( child, expanding_widgets_size, rem_height );
|
||||
left += spacing;
|
||||
rem -= expanding_widgets_size;
|
||||
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 {
|
||||
widget_move ( child, left, child->y );
|
||||
widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
|
||||
left += widget_get_width ( child );
|
||||
widget_resize ( child, child->w, b->widget.h );
|
||||
left += b->padding;
|
||||
left += spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
b->max_size += widget_padding_get_padding_width ( WIDGET ( b ) );
|
||||
}
|
||||
|
||||
static void box_draw ( widget *wid, cairo_t *draw )
|
||||
{
|
||||
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 ) ) {
|
||||
widget * child = (widget *) iter->data;
|
||||
widget_draw ( child, draw );
|
||||
}
|
||||
cairo_restore ( draw );
|
||||
}
|
||||
|
||||
static void box_free ( widget *wid )
|
||||
|
@ -206,15 +234,34 @@ static void box_free ( widget *wid )
|
|||
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 ) {
|
||||
return;
|
||||
}
|
||||
child->expand = expand;
|
||||
child->end = end;
|
||||
// Make sure box is width/heigh enough.
|
||||
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 );
|
||||
box->children = g_list_append ( box->children, (void *) child );
|
||||
box->children = g_list_sort ( box->children, box_sort_children );
|
||||
widget_update ( WIDGET ( box ) );
|
||||
}
|
||||
|
||||
|
@ -263,22 +310,22 @@ static gboolean box_motion_notify ( widget *wid, xcb_motion_notify_event_t *xme
|
|||
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 ) );
|
||||
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.free = box_free;
|
||||
b->widget.resize = box_resize;
|
||||
b->widget.update = box_update;
|
||||
b->widget.clicked = box_clicked;
|
||||
b->widget.motion_notify = box_motion_notify;
|
||||
b->widget.enabled = TRUE;
|
||||
// Initialize widget.
|
||||
widget_init ( WIDGET(b), name );
|
||||
b->type = type;
|
||||
b->widget.draw = box_draw;
|
||||
b->widget.free = box_free;
|
||||
b->widget.resize = box_resize;
|
||||
b->widget.update = box_update;
|
||||
b->widget.clicked = box_clicked;
|
||||
b->widget.motion_notify = box_motion_notify;
|
||||
b->widget.get_desired_height = box_get_desired_height;
|
||||
b->widget.enabled = TRUE;
|
||||
|
||||
b->spacing = rofi_theme_get_distance ( WIDGET(b), "spacing", DEFAULT_SPACING );
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -302,11 +349,3 @@ int box_get_fixed_pixels ( box *box )
|
|||
}
|
||||
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
148
source/widgets/container.c
Normal 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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,11 @@
|
|||
#include <widgets/listview.h>
|
||||
#include <widgets/scrollbar.h>
|
||||
|
||||
#include "settings.h"
|
||||
#include "theme.h"
|
||||
|
||||
#define DEFAULT_SPACING 2
|
||||
|
||||
struct _listview
|
||||
{
|
||||
widget widget;
|
||||
|
@ -51,10 +56,14 @@ struct _listview
|
|||
unsigned int req_elements;
|
||||
unsigned int cur_elements;
|
||||
|
||||
unsigned int padding;
|
||||
Distance spacing;
|
||||
unsigned int menu_lines;
|
||||
unsigned int max_displayed_lines;
|
||||
unsigned int menu_columns;
|
||||
unsigned int fixed_num_lines;
|
||||
unsigned int dynamic;
|
||||
unsigned int eh;
|
||||
unsigned int reverse;
|
||||
gboolean cycle;
|
||||
gboolean multi_select;
|
||||
|
||||
|
@ -71,8 +80,13 @@ struct _listview
|
|||
xcb_timestamp_t last_click;
|
||||
listview_mouse_activated_cb mouse_activated;
|
||||
void *mouse_activated_data;
|
||||
|
||||
|
||||
char *listview_name;
|
||||
};
|
||||
|
||||
static int listview_get_desired_height ( widget *wid );
|
||||
|
||||
static void listview_free ( widget *wid )
|
||||
{
|
||||
listview *lv = (listview *) wid;
|
||||
|
@ -81,6 +95,7 @@ static void listview_free ( widget *wid )
|
|||
}
|
||||
g_free ( lv->boxes );
|
||||
|
||||
g_free( lv->listview_name );
|
||||
widget_free ( WIDGET ( lv->scrollbar ) );
|
||||
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.
|
||||
scrollbar_set_max_value ( lv->scrollbar, lv->req_elements );
|
||||
scrollbar_set_handle_length ( lv->scrollbar, lv->cur_columns * lv->max_rows );
|
||||
scrollbar_set_handle ( lv->scrollbar, lv->selected );
|
||||
if ( lv->reverse ) {
|
||||
scrollbar_set_handle ( lv->scrollbar, lv->req_elements - lv->selected -1 );
|
||||
} else {
|
||||
scrollbar_set_handle ( lv->scrollbar, lv->selected );
|
||||
}
|
||||
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 ) {
|
||||
cairo_save ( draw );
|
||||
// Set new x/y possition.
|
||||
cairo_translate ( draw, wid->x, wid->y );
|
||||
unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset );
|
||||
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 ) ) ) {
|
||||
width -= lv->padding;
|
||||
width -= spacing_hori;
|
||||
width -= widget_get_width ( WIDGET ( lv->scrollbar ) );
|
||||
}
|
||||
unsigned int element_width = ( width ) / lv->cur_columns;
|
||||
for ( unsigned int i = 0; i < max; i++ ) {
|
||||
unsigned int ex = ( ( i ) / lv->max_rows ) * ( element_width + lv->padding );
|
||||
unsigned int ey = ( ( i ) % lv->max_rows ) * ( lv->element_height + lv->padding );
|
||||
textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
|
||||
unsigned int ex = left_offset + ( ( i ) / lv->max_rows ) * ( element_width + spacing_hori );
|
||||
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 );
|
||||
} 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 );
|
||||
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->scrollbar ), draw );
|
||||
cairo_restore ( draw );
|
||||
}
|
||||
widget_draw ( WIDGET ( lv->scrollbar ), draw );
|
||||
}
|
||||
|
||||
static void listview_recompute_elements ( listview *lv )
|
||||
|
@ -208,7 +238,9 @@ static void listview_recompute_elements ( listview *lv )
|
|||
if ( newne > 0 ) {
|
||||
for ( unsigned int i = lv->cur_elements; i < newne; i++ ) {
|
||||
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;
|
||||
|
@ -244,11 +276,21 @@ static void listview_resize ( widget *wid, short w, short h )
|
|||
listview *lv = (listview *) wid;
|
||||
lv->widget.w = MAX ( 0, w );
|
||||
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;
|
||||
|
||||
widget_move ( WIDGET ( lv->scrollbar ), lv->widget.w - widget_get_width ( WIDGET ( lv->scrollbar ) ), 0 );
|
||||
widget_resize ( WIDGET ( lv->scrollbar ), widget_get_width ( WIDGET ( lv->scrollbar ) ), h );
|
||||
if ( lv->scrollbar->widget.index == 0 ){
|
||||
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 );
|
||||
widget_queue_redraw ( wid );
|
||||
|
@ -310,24 +352,49 @@ static gboolean listview_motion_notify ( widget *wid, xcb_motion_notify_event_t
|
|||
|
||||
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 ) );
|
||||
lv->widget.free = listview_free;
|
||||
lv->widget.resize = listview_resize;
|
||||
lv->widget.draw = listview_draw;
|
||||
lv->widget.clicked = listview_clicked;
|
||||
lv->widget.motion_notify = listview_motion_notify;
|
||||
lv->widget.enabled = TRUE;
|
||||
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.resize = listview_resize;
|
||||
lv->widget.draw = listview_draw;
|
||||
lv->widget.clicked = listview_clicked;
|
||||
lv->widget.motion_notify = listview_motion_notify;
|
||||
lv->widget.get_desired_height = listview_get_desired_height;
|
||||
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 );
|
||||
lv->scrollbar->widget.parent = WIDGET ( lv );
|
||||
// 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->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;
|
||||
}
|
||||
|
||||
|
@ -335,7 +402,7 @@ listview *listview_create ( listview_update_callback cb, void *udata, unsigned i
|
|||
* Navigation commands.
|
||||
*/
|
||||
|
||||
void listview_nav_up ( listview *lv )
|
||||
static void listview_nav_up_int ( listview *lv )
|
||||
{
|
||||
if ( lv == NULL ) {
|
||||
return;
|
||||
|
@ -349,7 +416,7 @@ void listview_nav_up ( listview *lv )
|
|||
lv->selected--;
|
||||
widget_queue_redraw ( WIDGET ( lv ) );
|
||||
}
|
||||
void listview_nav_down ( listview *lv )
|
||||
static void listview_nav_down_int ( listview *lv )
|
||||
{
|
||||
if ( lv == NULL ) {
|
||||
return;
|
||||
|
@ -362,6 +429,23 @@ void listview_nav_down ( listview *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 )
|
||||
{
|
||||
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 ) {
|
||||
return;
|
||||
|
@ -409,7 +493,7 @@ void listview_nav_page_prev ( listview *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 ) {
|
||||
return;
|
||||
|
@ -424,50 +508,51 @@ void listview_nav_page_next ( listview *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;
|
||||
}
|
||||
int h = lv->menu_lines;
|
||||
if ( !( lv->fixed_num_lines ) ) {
|
||||
h = MIN ( lv->menu_lines, lv->req_elements );
|
||||
if ( lv->dynamic ) {
|
||||
h = MIN ( lv->menu_lines, lv->req_elements );
|
||||
} else {
|
||||
h = MIN ( lv->menu_lines, lv->max_displayed_lines );
|
||||
}
|
||||
}
|
||||
if ( h == 0 ) {
|
||||
return 0;
|
||||
if ( lv->dynamic && !lv->fixed_num_lines ){
|
||||
// Hide widget fully.
|
||||
return 0;
|
||||
}
|
||||
return widget_padding_get_padding_height ( WIDGET (lv) );
|
||||
}
|
||||
return h * lv->element_height + ( h - 1 ) * lv->padding;
|
||||
int height = widget_padding_get_padding_height ( WIDGET (lv) );
|
||||
height += h*(lv->element_height+spacing) - spacing;
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
void listview_set_show_scrollbar ( listview *lv, gboolean enabled )
|
||||
{
|
||||
if ( lv ) {
|
||||
if ( enabled ) {
|
||||
|
@ -479,19 +564,7 @@ void listview_set_hide_scrollbar ( listview *lv, gboolean enabled )
|
|||
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 )
|
||||
{
|
||||
if ( lv ) {
|
||||
|
@ -512,3 +585,37 @@ void listview_set_multi_select ( listview *lv, gboolean 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,24 +27,37 @@
|
|||
#include <glib.h>
|
||||
#include "widgets/scrollbar.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_free ( widget * );
|
||||
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 ) );
|
||||
|
||||
sb->widget.x = x;
|
||||
sb->widget.y = y;
|
||||
sb->widget.w = MAX ( 1, w );
|
||||
sb->widget.h = MAX ( 1, h );
|
||||
widget_init ( WIDGET (sb), name );
|
||||
sb->widget.x = 0;
|
||||
sb->widget.y = 0;
|
||||
sb->width = rofi_theme_get_distance ( WIDGET (sb), "handle-width", DEFAULT_SCROLLBAR_WIDTH );
|
||||
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.free = scrollbar_free;
|
||||
sb->widget.motion_notify = scrollbar_motion_notify;
|
||||
sb->widget.get_desired_height = scrollbar_get_desired_height;
|
||||
|
||||
sb->length = 10;
|
||||
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 )
|
||||
{
|
||||
scrollbar *sb = (scrollbar *) wid;
|
||||
unsigned int wh = widget_padding_get_remaining_height ( wid );
|
||||
// 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;
|
||||
double sec = ( ( r ) / (double) ( sb->length - 1 ) );
|
||||
unsigned int height = handle;
|
||||
unsigned int y = sb->pos * sec;
|
||||
// Set max pos.
|
||||
y = MIN ( y, wid->h - handle );
|
||||
y = MIN ( y, wh - handle );
|
||||
// Never go out of bar.
|
||||
height = MAX ( 2, height );
|
||||
// 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 );
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -29,19 +29,21 @@
|
|||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <math.h>
|
||||
#include "settings.h"
|
||||
#include "widgets/textbox.h"
|
||||
#include "keyb.h"
|
||||
#include "x11-helper.h"
|
||||
#include "mode.h"
|
||||
#include "view.h"
|
||||
|
||||
#include "theme.h"
|
||||
|
||||
#define DOT_OFFSET 15
|
||||
|
||||
static void textbox_draw ( widget *, cairo_t * );
|
||||
static void textbox_free ( widget * );
|
||||
static int textbox_get_width ( widget * );
|
||||
static int _textbox_get_height ( widget * );
|
||||
static void __textbox_update_pango_text ( textbox *tb );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
|
@ -50,26 +52,6 @@ static int _textbox_get_height ( widget * );
|
|||
*/
|
||||
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 */
|
||||
static PangoContext *p_context = NULL;
|
||||
/** The pango font metrics */
|
||||
|
@ -95,24 +77,34 @@ static void textbox_resize ( widget *wid, short w, short h )
|
|||
textbox *tb = (textbox *) wid;
|
||||
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,
|
||||
TextBoxFontType tbft, const char *text )
|
||||
textbox* textbox_create ( const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text )
|
||||
{
|
||||
textbox *tb = g_slice_new0 ( textbox );
|
||||
|
||||
widget_init ( WIDGET (tb), name );
|
||||
|
||||
tb->widget.draw = textbox_draw;
|
||||
tb->widget.free = textbox_free;
|
||||
tb->widget.resize = textbox_resize;
|
||||
tb->widget.get_width = textbox_get_width;
|
||||
tb->widget.get_height = _textbox_get_height;
|
||||
tb->widget.get_desired_height = textbox_get_desired_height;
|
||||
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->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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
TextBoxFontType t = tbft & STATE_MASK;
|
||||
|
@ -150,23 +154,19 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft )
|
|||
if ( t == ( URGENT | ACTIVE ) ) {
|
||||
t = ACTIVE;
|
||||
}
|
||||
RowColor *color = &( colors[t] );
|
||||
switch ( ( tbft & FMOD_MASK ) )
|
||||
{
|
||||
case HIGHLIGHT:
|
||||
tb->color_bg = color->hlbg;
|
||||
tb->color_fg = color->hlfg;
|
||||
widget_set_state ( WIDGET (tb), theme_prop_names[t][1]);
|
||||
break;
|
||||
case ALT:
|
||||
tb->color_bg = color->bgalt;
|
||||
tb->color_fg = color->fg;
|
||||
widget_set_state ( WIDGET (tb), theme_prop_names[t][2]);
|
||||
break;
|
||||
default:
|
||||
tb->color_bg = color->bg;
|
||||
tb->color_fg = color->fg;
|
||||
widget_set_state ( WIDGET (tb), theme_prop_names[t][0]);
|
||||
break;
|
||||
}
|
||||
if ( tb->tbft != tbft ) {
|
||||
if ( tb->tbft != tbft || tb->widget.state == NULL ) {
|
||||
tb->update = TRUE;
|
||||
widget_queue_redraw ( WIDGET ( tb ) );
|
||||
}
|
||||
|
@ -232,7 +232,9 @@ void textbox_text ( textbox *tb, const char *text )
|
|||
__textbox_update_pango_text ( tb );
|
||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||
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 ) );
|
||||
|
@ -246,7 +248,7 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
|||
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||
pango_layout_set_width ( tb->layout, -1 );
|
||||
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 {
|
||||
// set ellipsize
|
||||
|
@ -261,8 +263,9 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
|||
if ( tb->flags & TB_AUTOHEIGHT ) {
|
||||
// Width determines height!
|
||||
int tw = MAX ( 1, w );
|
||||
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tw - 2 * config.line_padding - offset ) );
|
||||
h = textbox_get_height ( tb );
|
||||
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tw - widget_padding_get_padding_width ( WIDGET (tb) ) - offset ) );
|
||||
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 ) {
|
||||
|
@ -273,7 +276,7 @@ void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
|
|||
}
|
||||
|
||||
// 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;
|
||||
widget_queue_redraw ( WIDGET ( tb ) );
|
||||
}
|
||||
|
@ -286,7 +289,6 @@ static void textbox_free ( widget *wid )
|
|||
g_source_remove ( tb->blink_timeout );
|
||||
tb->blink_timeout = 0;
|
||||
}
|
||||
|
||||
g_free ( tb->text );
|
||||
|
||||
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_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 );
|
||||
int font_height = textbox_get_font_height ( tb );
|
||||
|
||||
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 ) {
|
||||
__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 );
|
||||
pango_layout_get_cursor_pos ( tb->layout, offset - text, &pos, NULL );
|
||||
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.
|
||||
int x = config.line_padding + offset;
|
||||
int x = widget_padding_get_left ( WIDGET (tb) ) + offset;
|
||||
int y = 0;
|
||||
|
||||
if ( tb->flags & TB_RIGHT ) {
|
||||
int line_width = 0;
|
||||
// Get actual width.
|
||||
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 ) {
|
||||
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
|
||||
Color col = tb->color_bg;
|
||||
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
|
||||
cairo_paint ( tb->main_draw );
|
||||
// Set background transparency
|
||||
//cairo_set_source_rgba ( tb->main_draw, 0,0,0,0.0);
|
||||
//cairo_paint ( tb->main_draw );
|
||||
|
||||
col = tb->color_fg;
|
||||
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
|
||||
rofi_theme_get_color ( WIDGET ( tb ), "foreground", tb->main_draw);
|
||||
// draw the cursor
|
||||
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 );
|
||||
}
|
||||
|
||||
// Set ARGB
|
||||
// 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 );
|
||||
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 ) {
|
||||
cairo_set_source_rgba ( tb->main_draw, col.red, col.green, col.blue, col.alpha );
|
||||
}
|
||||
else if ( ( tb->tbft & HIGHLIGHT ) == HIGHLIGHT ) {
|
||||
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_fill ( tb->main_draw );
|
||||
|
@ -396,9 +402,8 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
|
|||
texbox_update ( tb );
|
||||
|
||||
/* Write buffer */
|
||||
|
||||
cairo_set_source_surface ( draw, tb->main_surface, tb->widget.x, tb->widget.y );
|
||||
cairo_rectangle ( draw, tb->widget.x, tb->widget.y, tb->widget.w, tb->widget.h );
|
||||
cairo_set_source_surface ( draw, tb->main_surface, 0,0 );
|
||||
cairo_rectangle ( draw, 0,0, tb->widget.w, tb->widget.h );
|
||||
cairo_fill ( draw );
|
||||
}
|
||||
|
||||
|
@ -709,47 +714,8 @@ gboolean textbox_append_char ( textbox *tb, const char *pad, const int pad_len )
|
|||
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 )
|
||||
{
|
||||
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 )
|
||||
|
@ -774,12 +740,9 @@ void textbox_cleanup ( void )
|
|||
int textbox_get_width ( widget *wid )
|
||||
{
|
||||
textbox *tb = (textbox *) wid;
|
||||
if ( !wid->expand ) {
|
||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
||||
return textbox_get_font_width ( tb ) + 2 * config.line_padding + offset;
|
||||
}
|
||||
return tb->widget.w;
|
||||
if ( tb->flags & TB_AUTOWIDTH ) {
|
||||
unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0;
|
||||
return textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( wid ) + offset;
|
||||
}
|
||||
return tb->widget.w;
|
||||
}
|
||||
|
@ -787,17 +750,14 @@ int textbox_get_width ( widget *wid )
|
|||
int _textbox_get_height ( widget *wid )
|
||||
{
|
||||
textbox *tb = (textbox *) wid;
|
||||
if ( !wid->expand ) {
|
||||
if ( tb->flags & TB_AUTOHEIGHT ) {
|
||||
return textbox_get_height ( tb );
|
||||
}
|
||||
return tb->widget.h;
|
||||
if ( tb->flags & TB_AUTOHEIGHT ) {
|
||||
return textbox_get_height ( tb );
|
||||
}
|
||||
return tb->widget.h;
|
||||
}
|
||||
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 )
|
||||
|
@ -814,14 +774,30 @@ int textbox_get_font_width ( const textbox *tb )
|
|||
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 );
|
||||
return ( width ) / (double) PANGO_SCALE;
|
||||
if ( char_height < 0 ){
|
||||
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 );
|
||||
return ( height ) / PANGO_SCALE + 2 * config.line_padding;
|
||||
return ( eh*height ) / PANGO_SCALE + widget_padding_get_padding_height ( WIDGET ( tb ) );
|
||||
}
|
||||
|
|
|
@ -1,6 +1,31 @@
|
|||
#include <glib.h>
|
||||
#include "widgets/widget.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 )
|
||||
{
|
||||
|
@ -20,12 +45,16 @@ void widget_resize ( widget *widget, short w, short h )
|
|||
{
|
||||
if ( widget != NULL ) {
|
||||
if ( widget->resize != NULL ) {
|
||||
widget->resize ( widget, w, h );
|
||||
if ( widget->w != w || widget->h != h ) {
|
||||
widget->resize ( widget, w, h );
|
||||
}
|
||||
}
|
||||
else {
|
||||
widget->w = w;
|
||||
widget->h = h;
|
||||
}
|
||||
// On a resize we always want to udpate.
|
||||
widget_queue_redraw ( widget );
|
||||
}
|
||||
}
|
||||
void widget_move ( widget *widget, short x, short y )
|
||||
|
@ -49,6 +78,7 @@ void widget_enable ( widget *widget )
|
|||
if ( widget && !widget->enabled ) {
|
||||
widget->enabled = TRUE;
|
||||
widget_update ( widget );
|
||||
widget_update ( widget->parent );
|
||||
}
|
||||
}
|
||||
void widget_disable ( widget *widget )
|
||||
|
@ -56,20 +86,91 @@ void widget_disable ( widget *widget )
|
|||
if ( widget && widget->enabled ) {
|
||||
widget->enabled = FALSE;
|
||||
widget_update ( widget );
|
||||
widget_update ( widget->parent );
|
||||
}
|
||||
}
|
||||
void widget_draw ( widget *widget, cairo_t *d )
|
||||
{
|
||||
// Check if enabled and if draw is implemented.
|
||||
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->need_redraw = FALSE;
|
||||
|
||||
cairo_restore ( d );
|
||||
}
|
||||
}
|
||||
void widget_free ( widget *wid )
|
||||
{
|
||||
if ( wid && wid->free ) {
|
||||
wid->free ( wid );
|
||||
if ( wid ) {
|
||||
if ( wid->name ) {
|
||||
g_free ( wid->name );
|
||||
}
|
||||
if ( wid->free ) {
|
||||
wid->free ( wid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,8 +216,6 @@ void widget_update ( widget *widget )
|
|||
if ( widget->update ) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -194,6 +194,8 @@ static XrmOption xrmOptions[] = {
|
|||
"Click outside the window to exit", CONFIG_DEFAULT },
|
||||
{ xrm_Boolean, "show-match", { .snum = &config.show_match }, NULL,
|
||||
"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 */
|
||||
|
|
|
@ -22,6 +22,16 @@ unsigned int test =0;
|
|||
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 )
|
||||
{
|
||||
|
@ -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 )
|
||||
{
|
||||
{
|
||||
box *b = box_create ( BOX_HORIZONTAL, 0, 0, 100, 20 );
|
||||
box_set_padding ( b, 5 );
|
||||
box *b = box_create ( "box", BOX_HORIZONTAL );
|
||||
//box_set_padding ( b, 5 );
|
||||
widget_resize ( WIDGET (b), 100, 20);
|
||||
|
||||
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.
|
||||
TASSERTE ( wid1->h, 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 );
|
||||
widget *wid2 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid2 ) );
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, FALSE );
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, 1 );
|
||||
TASSERTE ( wid1->h, 20);
|
||||
TASSERTE ( wid1->w, 47);
|
||||
TASSERTE ( wid1->w, 49);
|
||||
TASSERTE ( wid2->h, 20);
|
||||
TASSERTE ( wid2->w, 48);
|
||||
TASSERTE ( wid2->w, 49);
|
||||
|
||||
widget *wid3 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid3 ) );
|
||||
box_add ( b , WIDGET( wid3 ), FALSE, FALSE );
|
||||
box_add ( b , WIDGET( wid3 ), FALSE, 2 );
|
||||
TASSERTE ( wid1->h, 20);
|
||||
TASSERTE ( wid1->w, 45);
|
||||
TASSERTE ( wid1->w, 48);
|
||||
TASSERTE ( wid2->h, 20);
|
||||
TASSERTE ( wid2->w, 45);
|
||||
TASSERTE ( wid2->w, 48);
|
||||
|
||||
widget_resize ( WIDGET (wid3) , 20, 10 );
|
||||
// TODO should this happen automagically?
|
||||
widget_update ( WIDGET ( b ) ) ;
|
||||
TASSERTE ( wid1->h, 20);
|
||||
TASSERTE ( wid1->w, 35);
|
||||
TASSERTE ( wid1->w, 38);
|
||||
TASSERTE ( wid2->h, 20);
|
||||
TASSERTE ( wid2->w, 35);
|
||||
TASSERTE ( wid2->w, 38);
|
||||
TASSERTE ( wid3->h, 20);
|
||||
TASSERTE ( wid3->w, 20);
|
||||
|
||||
widget_resize ( WIDGET (b ), 200, 20 );
|
||||
TASSERTE ( wid1->h, 20);
|
||||
TASSERTE ( wid1->w, 85);
|
||||
TASSERTE ( wid1->w, 88);
|
||||
TASSERTE ( wid2->h, 20);
|
||||
TASSERTE ( wid2->w, 85);
|
||||
TASSERTE ( wid2->w, 88);
|
||||
TASSERTE ( wid3->h, 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_enable ( WIDGET ( wid4 ) );
|
||||
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);
|
||||
widget *wid5 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid5 ) );
|
||||
widget_resize ( WIDGET ( wid5 ), 20, 20 );
|
||||
box_add ( b , WIDGET( wid5 ), TRUE, TRUE );
|
||||
TASSERTE ( wid5->x, 128);
|
||||
box_add ( b , WIDGET( wid5 ), TRUE, 6 );
|
||||
TASSERTE ( wid5->x, 149);
|
||||
widget_free ( WIDGET ( b ) );
|
||||
}
|
||||
{
|
||||
box *b = box_create ( BOX_VERTICAL, 0, 0, 20, 100 );
|
||||
box_set_padding ( b, 5 );
|
||||
box *b = box_create ( "box", BOX_VERTICAL );
|
||||
widget_resize ( WIDGET (b), 20, 100);
|
||||
//box_set_padding ( b, 5 );
|
||||
|
||||
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.
|
||||
TASSERTE ( wid1->h, 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 );
|
||||
widget *wid2 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid2 ) );
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, FALSE );
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, 1 );
|
||||
TASSERTE ( wid1->w, 20);
|
||||
TASSERTE ( wid1->h, 47);
|
||||
TASSERTE ( wid1->h, 49);
|
||||
TASSERTE ( wid2->w, 20);
|
||||
TASSERTE ( wid2->h, 48);
|
||||
TASSERTE ( wid2->h, 49);
|
||||
|
||||
widget *wid3 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid3 ) );
|
||||
box_add ( b , WIDGET( wid3 ), FALSE, FALSE );
|
||||
box_add ( b , WIDGET( wid3 ), FALSE, 2 );
|
||||
TASSERTE ( wid1->w, 20);
|
||||
TASSERTE ( wid1->h, 45);
|
||||
TASSERTE ( wid1->h, 48);
|
||||
TASSERTE ( wid2->w, 20);
|
||||
TASSERTE ( wid2->h, 45);
|
||||
TASSERTE ( wid2->h, 48);
|
||||
|
||||
widget_resize ( WIDGET (wid3) , 10, 20 );
|
||||
// TODO should this happen automagically?
|
||||
widget_update ( WIDGET ( b ) ) ;
|
||||
TASSERTE ( wid1->w, 20);
|
||||
TASSERTE ( wid1->h, 35);
|
||||
TASSERTE ( wid1->h, 48);
|
||||
TASSERTE ( wid2->w, 20);
|
||||
TASSERTE ( wid2->h, 35);
|
||||
TASSERTE ( wid2->h, 48);
|
||||
TASSERTE ( wid3->w, 20);
|
||||
TASSERTE ( wid3->h, 20);
|
||||
TASSERTE ( wid3->h, 0);
|
||||
|
||||
widget_resize ( WIDGET (b ), 20, 200 );
|
||||
TASSERTE ( wid1->w, 20);
|
||||
TASSERTE ( wid1->h, 85);
|
||||
TASSERTE ( wid1->h, 98);
|
||||
TASSERTE ( wid2->w, 20);
|
||||
TASSERTE ( wid2->h, 85);
|
||||
TASSERTE ( wid2->h, 98);
|
||||
TASSERTE ( wid3->w, 20);
|
||||
TASSERTE ( wid3->h, 20);
|
||||
TASSERTE ( box_get_fixed_pixels ( b ) , 30 );
|
||||
// has no height, gets no height.
|
||||
TASSERTE ( wid3->h, 0);
|
||||
TASSERTE ( box_get_fixed_pixels ( b ) , 4 );
|
||||
widget *wid4 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid4 ) );
|
||||
widget_resize ( WIDGET ( wid4 ), 20, 20 );
|
||||
box_add ( b , WIDGET( wid4 ), FALSE, TRUE );
|
||||
TASSERTE ( wid4->y, 200-20);
|
||||
box_add ( b , WIDGET( wid4 ), FALSE, 5 );
|
||||
TASSERTE ( wid4->y, 200);
|
||||
widget *wid5 = g_malloc0(sizeof(widget));
|
||||
widget_enable ( WIDGET ( wid5 ) );
|
||||
widget_resize ( WIDGET ( wid5 ), 20, 20 );
|
||||
box_add ( b , WIDGET( wid5 ), TRUE, TRUE );
|
||||
TASSERTE ( wid5->y, 128);
|
||||
box_add ( b , WIDGET( wid5 ), TRUE, 6 );
|
||||
TASSERTE ( wid5->y, 136);
|
||||
widget_free ( WIDGET ( b ) );
|
||||
}
|
||||
{
|
||||
box *b = box_create ( BOX_VERTICAL, 0, 0, 20, 100 );
|
||||
box_set_padding ( b, 5 );
|
||||
box *b = box_create ( "box", BOX_VERTICAL );
|
||||
widget_resize ( WIDGET (b), 20, 100);
|
||||
//box_set_padding ( b, 5 );
|
||||
widget *wid1 = g_malloc0(sizeof(widget));
|
||||
widget_enable(wid1);
|
||||
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_enable(wid2);
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, FALSE );
|
||||
box_add ( b , WIDGET( wid2 ), TRUE, 1 );
|
||||
|
||||
xcb_button_press_event_t xce;
|
||||
xce.event_x = 10;
|
||||
|
@ -169,7 +183,7 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
|
|||
|
||||
xce.event_y = 50;
|
||||
TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 0);
|
||||
xce.event_y = 45;
|
||||
xce.event_y = 48;
|
||||
TASSERTE ( widget_clicked ( WIDGET(b), &xce ), 1);
|
||||
widget_disable ( wid2 );
|
||||
xce.event_y = 60;
|
||||
|
|
|
@ -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 rofi_view_get_current_monitor ( int *width, int *height )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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_max_value ( NULL, 10 );
|
||||
|
|
|
@ -24,12 +24,10 @@ unsigned int normal_window_mode = 0;
|
|||
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 )
|
||||
{
|
||||
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 );
|
||||
textbox_set_pango_context ( p );
|
||||
|
||||
textbox *box = textbox_create ( TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, 0, 0, -1, -1,
|
||||
NORMAL, "test" );
|
||||
textbox *box = textbox_create ( "textbox", TB_EDITABLE | TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "test" );
|
||||
TASSERT ( box != NULL );
|
||||
|
||||
textbox_keybinding ( box, MOVE_END );
|
||||
|
|
|
@ -12,7 +12,19 @@ unsigned int test =0;
|
|||
assert ( 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 )
|
||||
{
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
! Copyright: Dave Davenport
|
||||
! ------------------------------------------------------------------------------
|
||||
! "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
|
||||
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
|
||||
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
|
||||
rofi.color-window: argb:dd000021, #dbdfbc, #dbdfbc
|
||||
! "Separator style (none, dash, solid)" Set from: XResources
|
||||
|
|
Loading…
Reference in a new issue