mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
More line fixing.
This commit is contained in:
parent
b18d68eff2
commit
31fe5759b8
12 changed files with 156 additions and 340 deletions
|
@ -58,8 +58,7 @@ static void combi_mode_parse_switchers ( Switcher *sw )
|
||||||
// Make a copy, as strtok will modify it.
|
// Make a copy, as strtok will modify it.
|
||||||
char *switcher_str = g_strdup ( config.combi_modi );
|
char *switcher_str = g_strdup ( config.combi_modi );
|
||||||
// Split token on ','. This modifies switcher_str.
|
// Split token on ','. This modifies switcher_str.
|
||||||
for ( char *token = strtok_r ( switcher_str, ",", &savept );
|
for ( char *token = strtok_r ( switcher_str, ",", &savept ); token != NULL;
|
||||||
token != NULL;
|
|
||||||
token = strtok_r ( NULL, ",", &savept ) ) {
|
token = strtok_r ( NULL, ",", &savept ) ) {
|
||||||
// Resize and add entry.
|
// Resize and add entry.
|
||||||
pd->switchers = (Switcher * *) g_realloc ( pd->switchers,
|
pd->switchers = (Switcher * *) g_realloc ( pd->switchers,
|
||||||
|
@ -164,9 +163,7 @@ static SwitcherMode combi_mode_result ( int mretv, char **input, unsigned int se
|
||||||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
||||||
if ( selected_line >= pd->starts[i] &&
|
if ( selected_line >= pd->starts[i] &&
|
||||||
selected_line < ( pd->starts[i] + pd->lengths[i] ) ) {
|
selected_line < ( pd->starts[i] + pd->lengths[i] ) ) {
|
||||||
return pd->switchers[i]->result ( mretv,
|
return pd->switchers[i]->result ( mretv, input, selected_line - pd->starts[i],
|
||||||
input,
|
|
||||||
selected_line - pd->starts[i],
|
|
||||||
pd->switchers[i] );
|
pd->switchers[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,11 +176,8 @@ static int combi_mode_match ( char **tokens, const char *input,
|
||||||
|
|
||||||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
||||||
if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
|
if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
|
||||||
return pd->switchers[i]->token_match ( tokens,
|
return pd->switchers[i]->token_match ( tokens, input, case_sensitive,
|
||||||
input,
|
index - pd->starts[i], pd->switchers[i] );
|
||||||
case_sensitive,
|
|
||||||
index - pd->starts[i],
|
|
||||||
pd->switchers[i] );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
abort ();
|
abort ();
|
||||||
|
@ -193,11 +187,9 @@ static const char * combi_mgrv ( unsigned int selected_line, void *sw, int *stat
|
||||||
{
|
{
|
||||||
CombiModePrivateData *pd = ( (Switcher *) sw )->private_data;
|
CombiModePrivateData *pd = ( (Switcher *) sw )->private_data;
|
||||||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
|
||||||
if ( selected_line >= pd->starts[i] && selected_line <
|
if ( selected_line >= pd->starts[i] && selected_line < ( pd->starts[i] + pd->lengths[i] ) ) {
|
||||||
( pd->starts[i] + pd->lengths[i] ) ) {
|
|
||||||
g_free ( pd->cache );
|
g_free ( pd->cache );
|
||||||
pd->cache = g_strdup_printf ( "(%s) %s",
|
pd->cache = g_strdup_printf ( "(%s) %s", pd->switchers[i]->name,
|
||||||
pd->switchers[i]->name,
|
|
||||||
pd->switchers[i]->mgrv ( selected_line - pd->starts[i],
|
pd->switchers[i]->mgrv ( selected_line - pd->starts[i],
|
||||||
(void *) pd->switchers[i], state ) );
|
(void *) pd->switchers[i], state ) );
|
||||||
return pd->cache;
|
return pd->cache;
|
||||||
|
|
|
@ -98,9 +98,7 @@ static char ** dmenu_mode_get_data ( unsigned int *length, Switcher *sw )
|
||||||
static void parse_pair ( char *input, struct range_pair *item )
|
static void parse_pair ( char *input, struct range_pair *item )
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for ( char *token = strsep ( &input, "-" );
|
for ( char *token = strsep ( &input, "-" ); token != NULL; token = strsep ( &input, "-" ) ) {
|
||||||
token != NULL;
|
|
||||||
token = strsep ( &input, "-" ) ) {
|
|
||||||
if ( index == 0 ) {
|
if ( index == 0 ) {
|
||||||
item->start = item->stop = (unsigned int) strtoul ( token, NULL, 10 );
|
item->start = item->stop = (unsigned int) strtoul ( token, NULL, 10 );
|
||||||
index++;
|
index++;
|
||||||
|
@ -119,9 +117,7 @@ static void parse_pair ( char *input, struct range_pair *item )
|
||||||
static void parse_ranges ( char *input, struct range_pair **list, unsigned int *length )
|
static void parse_ranges ( char *input, struct range_pair **list, unsigned int *length )
|
||||||
{
|
{
|
||||||
char *endp;
|
char *endp;
|
||||||
for ( char *token = strtok_r ( input, ",", &endp );
|
for ( char *token = strtok_r ( input, ",", &endp ); token != NULL; token = strtok_r ( NULL, ",", &endp ) ) {
|
||||||
token != NULL;
|
|
||||||
token = strtok_r ( NULL, ",", &endp ) ) {
|
|
||||||
// Make space.
|
// Make space.
|
||||||
*list = g_realloc ( ( *list ), ( ( *length ) + 1 ) * sizeof ( struct range_pair ) );
|
*list = g_realloc ( ( *list ), ( ( *length ) + 1 ) * sizeof ( struct range_pair ) );
|
||||||
// Parse a single pair.
|
// Parse a single pair.
|
||||||
|
@ -318,8 +314,7 @@ int dmenu_switcher_dialog ( void )
|
||||||
|
|
||||||
do {
|
do {
|
||||||
unsigned int next_pos = pd->selected_line;
|
unsigned int next_pos = pd->selected_line;
|
||||||
int mretv = menu ( &dmenu_mode, &input, pd->prompt,
|
int mretv = menu ( &dmenu_mode, &input, pd->prompt, &( pd->selected_line ), &next_pos, pd->message );
|
||||||
&( pd->selected_line ), &next_pos, pd->message );
|
|
||||||
// Special behavior.
|
// Special behavior.
|
||||||
// TODO clean this up!
|
// TODO clean this up!
|
||||||
if ( only_selected ) {
|
if ( only_selected ) {
|
||||||
|
@ -327,11 +322,8 @@ int dmenu_switcher_dialog ( void )
|
||||||
* Select item mode.
|
* Select item mode.
|
||||||
*/
|
*/
|
||||||
restart = 1;
|
restart = 1;
|
||||||
if ( ( mretv & ( MENU_OK | MENU_QUICK_SWITCH ) ) && cmd_list[pd->selected_line] !=
|
if ( ( mretv & ( MENU_OK | MENU_QUICK_SWITCH ) ) && cmd_list[pd->selected_line] != NULL ) {
|
||||||
NULL ) {
|
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
|
||||||
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line],
|
|
||||||
pd->selected_line,
|
|
||||||
input );
|
|
||||||
retv = TRUE;
|
retv = TRUE;
|
||||||
if ( ( mretv & MENU_QUICK_SWITCH ) ) {
|
if ( ( mretv & MENU_QUICK_SWITCH ) ) {
|
||||||
retv = 10 + ( mretv & MENU_LOWER_MASK );
|
retv = 10 + ( mretv & MENU_LOWER_MASK );
|
||||||
|
@ -349,9 +341,7 @@ int dmenu_switcher_dialog ( void )
|
||||||
restart = FALSE;
|
restart = FALSE;
|
||||||
// Normal mode
|
// Normal mode
|
||||||
if ( ( mretv & MENU_OK ) && cmd_list[pd->selected_line] != NULL ) {
|
if ( ( mretv & MENU_OK ) && cmd_list[pd->selected_line] != NULL ) {
|
||||||
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line],
|
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
|
||||||
pd->selected_line,
|
|
||||||
input );
|
|
||||||
if ( ( mretv & MENU_SHIFT ) ) {
|
if ( ( mretv & MENU_SHIFT ) ) {
|
||||||
restart = TRUE;
|
restart = TRUE;
|
||||||
// Move to next line.
|
// Move to next line.
|
||||||
|
@ -372,9 +362,7 @@ int dmenu_switcher_dialog ( void )
|
||||||
}
|
}
|
||||||
// Quick switch with entry selected.
|
// Quick switch with entry selected.
|
||||||
else if ( ( mretv & MENU_QUICK_SWITCH ) && pd->selected_line < UINT32_MAX ) {
|
else if ( ( mretv & MENU_QUICK_SWITCH ) && pd->selected_line < UINT32_MAX ) {
|
||||||
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line],
|
dmenu_output_formatted_line ( pd->format, cmd_list[pd->selected_line], pd->selected_line, input );
|
||||||
pd->selected_line,
|
|
||||||
input );
|
|
||||||
|
|
||||||
restart = FALSE;
|
restart = FALSE;
|
||||||
retv = 10 + ( mretv & MENU_LOWER_MASK );
|
retv = 10 + ( mretv & MENU_LOWER_MASK );
|
||||||
|
|
|
@ -56,12 +56,9 @@ static inline void execsh ( const char *cmd, int run_in_term )
|
||||||
helper_parse_setup ( config.run_command, &args, &argc, "{cmd}", cmd, NULL );
|
helper_parse_setup ( config.run_command, &args, &argc, "{cmd}", cmd, NULL );
|
||||||
}
|
}
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
g_spawn_async ( NULL, args, NULL,
|
g_spawn_async ( NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error );
|
||||||
G_SPAWN_SEARCH_PATH,
|
|
||||||
NULL, NULL, NULL, &error );
|
|
||||||
if ( error != NULL ) {
|
if ( error != NULL ) {
|
||||||
char *msg = g_strdup_printf ( "Failed to execute: '%s'\nError: '%s'", cmd,
|
char *msg = g_strdup_printf ( "Failed to execute: '%s'\nError: '%s'", cmd, error->message );
|
||||||
error->message );
|
|
||||||
error_dialog ( msg, FALSE );
|
error_dialog ( msg, FALSE );
|
||||||
g_free ( msg );
|
g_free ( msg );
|
||||||
// print error.
|
// print error.
|
||||||
|
@ -187,18 +184,14 @@ static char ** get_apps ( unsigned int *length )
|
||||||
|
|
||||||
path = g_strdup ( getenv ( "PATH" ) );
|
path = g_strdup ( getenv ( "PATH" ) );
|
||||||
|
|
||||||
for ( const char *dirname = strtok ( path, ":" );
|
for ( const char *dirname = strtok ( path, ":" ); dirname != NULL; dirname = strtok ( NULL, ":" ) ) {
|
||||||
dirname != NULL;
|
|
||||||
dirname = strtok ( NULL, ":" ) ) {
|
|
||||||
DIR *dir = opendir ( dirname );
|
DIR *dir = opendir ( dirname );
|
||||||
|
|
||||||
if ( dir != NULL ) {
|
if ( dir != NULL ) {
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
|
|
||||||
while ( ( dent = readdir ( dir ) ) != NULL ) {
|
while ( ( dent = readdir ( dir ) ) != NULL ) {
|
||||||
if ( dent->d_type != DT_REG &&
|
if ( dent->d_type != DT_REG && dent->d_type != DT_LNK && dent->d_type != DT_UNKNOWN ) {
|
||||||
dent->d_type != DT_LNK &&
|
|
||||||
dent->d_type != DT_UNKNOWN ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Skip dot files.
|
// Skip dot files.
|
||||||
|
@ -240,9 +233,7 @@ static char ** get_apps ( unsigned int *length )
|
||||||
}
|
}
|
||||||
// TODO: check this is still fast enough. (takes 1ms on laptop.)
|
// TODO: check this is still fast enough. (takes 1ms on laptop.)
|
||||||
if ( ( *length ) > num_favorites ) {
|
if ( ( *length ) > num_favorites ) {
|
||||||
g_qsort_with_data ( &retv[num_favorites], ( *length ) - num_favorites, sizeof ( char* ),
|
g_qsort_with_data ( &retv[num_favorites], ( *length ) - num_favorites, sizeof ( char* ), sort_func, NULL );
|
||||||
sort_func,
|
|
||||||
NULL );
|
|
||||||
}
|
}
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
|
|
||||||
|
|
|
@ -173,8 +173,7 @@ Switcher *script_switcher_parse_setup ( const char *str )
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
char *parse = g_strdup ( str );
|
char *parse = g_strdup ( str );
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
for ( char *token = strtok_r ( parse, ":", &endp ); token != NULL;
|
for ( char *token = strtok_r ( parse, ":", &endp ); token != NULL; token = strtok_r ( NULL, ":", &endp ) ) {
|
||||||
token = strtok_r ( NULL, ":", &endp ) ) {
|
|
||||||
if ( index == 0 ) {
|
if ( index == 0 ) {
|
||||||
g_strlcpy ( sw->name, token, 32 );
|
g_strlcpy ( sw->name, token, 32 );
|
||||||
}
|
}
|
||||||
|
@ -197,8 +196,7 @@ Switcher *script_switcher_parse_setup ( const char *str )
|
||||||
|
|
||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
fprintf ( stderr, "The script command '%s' has %u options, but needs 2: <name>:<script>.\n",
|
fprintf ( stderr, "The script command '%s' has %u options, but needs 2: <name>:<script>.\n", str, index );
|
||||||
str, index );
|
|
||||||
script_switcher_free ( sw );
|
script_switcher_free ( sw );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,10 @@ static inline int execshssh ( const char *host )
|
||||||
helper_parse_setup ( config.ssh_command, &args, &argsv, "{host}", host, NULL );
|
helper_parse_setup ( config.ssh_command, &args, &argsv, "{host}", host, NULL );
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
g_spawn_async ( NULL, args, NULL,
|
g_spawn_async ( NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error );
|
||||||
G_SPAWN_SEARCH_PATH,
|
|
||||||
NULL, NULL, NULL, &error );
|
|
||||||
|
|
||||||
if ( error != NULL ) {
|
if ( error != NULL ) {
|
||||||
char *msg = g_strdup_printf ( "Failed to execute: 'ssh %s'\nError: '%s'", host,
|
char *msg = g_strdup_printf ( "Failed to execute: 'ssh %s'\nError: '%s'", host, error->message );
|
||||||
error->message );
|
|
||||||
error_dialog ( msg, FALSE );
|
error_dialog ( msg, FALSE );
|
||||||
g_free ( msg );
|
g_free ( msg );
|
||||||
// print error.
|
// print error.
|
||||||
|
@ -261,9 +258,7 @@ static char ** get_ssh ( unsigned int *length )
|
||||||
|
|
||||||
// TODO: check this is still fast enough. (takes 1ms on laptop.)
|
// TODO: check this is still fast enough. (takes 1ms on laptop.)
|
||||||
if ( ( *length ) > num_favorites ) {
|
if ( ( *length ) > num_favorites ) {
|
||||||
g_qsort_with_data ( &retv[num_favorites], ( *length ) - num_favorites, sizeof ( char* ),
|
g_qsort_with_data ( &retv[num_favorites], ( *length ) - num_favorites, sizeof ( char* ), ssh_sort_func, NULL );
|
||||||
ssh_sort_func,
|
|
||||||
NULL );
|
|
||||||
}
|
}
|
||||||
g_free ( path );
|
g_free ( path );
|
||||||
|
|
||||||
|
|
|
@ -269,9 +269,7 @@ static client* window_client ( Display *display, Window win )
|
||||||
|
|
||||||
c->states = window_get_atom_prop ( display, win, netatoms[_NET_WM_STATE], c->state, CLIENTSTATE );
|
c->states = window_get_atom_prop ( display, win, netatoms[_NET_WM_STATE], c->state, CLIENTSTATE );
|
||||||
|
|
||||||
c->window_types =
|
c->window_types = window_get_atom_prop ( display, win, netatoms[_NET_WM_WINDOW_TYPE], c->window_type, CLIENTWINDOWTYPE );
|
||||||
window_get_atom_prop ( display, win, netatoms[_NET_WM_WINDOW_TYPE], c->window_type,
|
|
||||||
CLIENTWINDOWTYPE );
|
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
if ( ( name = window_get_text_prop ( display, c->window, netatoms[_NET_WM_NAME] ) ) && name ) {
|
if ( ( name = window_get_text_prop ( display, c->window, netatoms[_NET_WM_NAME] ) ) && name ) {
|
||||||
|
@ -283,8 +281,7 @@ static client* window_client ( Display *display, Window win )
|
||||||
XFree ( name );
|
XFree ( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
name =
|
name = window_get_text_prop ( display, c->window, XInternAtom ( display, "WM_WINDOW_ROLE", False ) );
|
||||||
window_get_text_prop ( display, c->window, XInternAtom ( display, "WM_WINDOW_ROLE", False ) );
|
|
||||||
|
|
||||||
if ( name != NULL ) {
|
if ( name != NULL ) {
|
||||||
snprintf ( c->role, CLIENTROLE, "%s", name );
|
snprintf ( c->role, CLIENTROLE, "%s", name );
|
||||||
|
@ -392,21 +389,18 @@ static char ** _window_mode_get_data ( unsigned int *length, Switcher *sw, unsig
|
||||||
pd->config_i3_mode = i3_support_initialize ( display );
|
pd->config_i3_mode = i3_support_initialize ( display );
|
||||||
|
|
||||||
// Get the active window so we can highlight this.
|
// Get the active window so we can highlight this.
|
||||||
if ( !( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type,
|
if ( !( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, &count, &curr_win_id, sizeof ( Window ) )
|
||||||
&count, &curr_win_id, sizeof ( Window ) )
|
|
||||||
&& type == XA_WINDOW && count > 0 ) ) {
|
&& type == XA_WINDOW && count > 0 ) ) {
|
||||||
curr_win_id = 0;
|
curr_win_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current desktop.
|
// Get the current desktop.
|
||||||
unsigned long current_desktop = 0;
|
unsigned long current_desktop = 0;
|
||||||
if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_CURRENT_DESKTOP],
|
if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_CURRENT_DESKTOP], ¤t_desktop, 1 ) ) {
|
||||||
¤t_desktop, 1 ) ) {
|
|
||||||
current_desktop = 0;
|
current_desktop = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( window_get_prop ( display, root, netatoms[_NET_CLIENT_LIST_STACKING],
|
if ( window_get_prop ( display, root, netatoms[_NET_CLIENT_LIST_STACKING], &type, &nwins, wins, 100 * sizeof ( Window ) )
|
||||||
&type, &nwins, wins, 100 * sizeof ( Window ) )
|
|
||||||
&& type == XA_WINDOW ) {
|
&& type == XA_WINDOW ) {
|
||||||
char pattern[50];
|
char pattern[50];
|
||||||
int i;
|
int i;
|
||||||
|
@ -443,8 +437,7 @@ static char ** _window_mode_get_data ( unsigned int *length, Switcher *sw, unsig
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create pattern for printing the line.
|
// Create pattern for printing the line.
|
||||||
if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_NUMBER_OF_DESKTOPS],
|
if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_NUMBER_OF_DESKTOPS], &desktops, 1 ) ) {
|
||||||
&desktops, 1 ) ) {
|
|
||||||
desktops = 1;
|
desktops = 1;
|
||||||
}
|
}
|
||||||
if ( pd->config_i3_mode ) {
|
if ( pd->config_i3_mode ) {
|
||||||
|
@ -466,13 +459,10 @@ static char ** _window_mode_get_data ( unsigned int *length, Switcher *sw, unsig
|
||||||
unsigned long wmdesktop;
|
unsigned long wmdesktop;
|
||||||
char desktop[5];
|
char desktop[5];
|
||||||
desktop[0] = 0;
|
desktop[0] = 0;
|
||||||
char *line = g_malloc ( strlen ( c->title ) + strlen (
|
char *line = g_malloc ( strlen ( c->title ) + strlen ( c->class ) + classfield + 50 );
|
||||||
c->class ) + classfield + 50 );
|
|
||||||
if ( !pd->config_i3_mode ) {
|
if ( !pd->config_i3_mode ) {
|
||||||
// find client's desktop.
|
// find client's desktop.
|
||||||
if ( !window_get_cardinal_prop ( display, c->window,
|
if ( !window_get_cardinal_prop ( display, c->window, netatoms[_NET_WM_DESKTOP], &wmdesktop, 1 ) ) {
|
||||||
netatoms[_NET_WM_DESKTOP], &wmdesktop,
|
|
||||||
1 ) ) {
|
|
||||||
// Assume the client is on all desktops.
|
// Assume the client is on all desktops.
|
||||||
wmdesktop = 0xFFFFFFFF;
|
wmdesktop = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
@ -533,13 +523,11 @@ static SwitcherMode window_mode_result ( int mretv, G_GNUC_UNUSED char **input,
|
||||||
Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) );
|
Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) );
|
||||||
// Change to the desktop of the selected window/client.
|
// Change to the desktop of the selected window/client.
|
||||||
// TODO: get rid of strtol
|
// TODO: get rid of strtol
|
||||||
window_send_message ( display, root, root, netatoms[_NET_CURRENT_DESKTOP],
|
window_send_message ( display, root, root, netatoms[_NET_CURRENT_DESKTOP], strtol ( rmpd->cmd_list[selected_line], NULL, 10 ),
|
||||||
strtol ( rmpd->cmd_list[selected_line], NULL, 10 ),
|
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask, 0 );
|
SubstructureNotifyMask | SubstructureRedirectMask, 0 );
|
||||||
XSync ( display, False );
|
XSync ( display, False );
|
||||||
|
|
||||||
window_send_message ( display, root, rmpd->ids->array[selected_line],
|
window_send_message ( display, root, rmpd->ids->array[selected_line], netatoms[_NET_ACTIVE_WINDOW], 2, // 2 = pager
|
||||||
netatoms[_NET_ACTIVE_WINDOW], 2, // 2 = pager
|
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask, 0 );
|
SubstructureNotifyMask | SubstructureRedirectMask, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,10 +111,8 @@ void parse_keys_abe ( void )
|
||||||
abe[iter].num_bindings = 0;
|
abe[iter].num_bindings = 0;
|
||||||
|
|
||||||
// Iter over bindings.
|
// Iter over bindings.
|
||||||
for ( char *entry = strtok_r ( keystr, ",", &sp ); entry != NULL;
|
for ( char *entry = strtok_r ( keystr, ",", &sp ); entry != NULL; entry = strtok_r ( NULL, ",", &sp ) ) {
|
||||||
entry = strtok_r ( NULL, ",", &sp ) ) {
|
abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) );
|
||||||
abe[iter].kb =
|
|
||||||
g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) );
|
|
||||||
KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] );
|
KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] );
|
||||||
x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ) );
|
x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ) );
|
||||||
abe[iter].num_bindings++;
|
abe[iter].num_bindings++;
|
||||||
|
|
|
@ -360,10 +360,9 @@ static void menu_calculate_rows_columns ( MenuState *state )
|
||||||
|
|
||||||
// Calculate the number or rows. We do this by getting the num_lines rounded up to X columns
|
// Calculate the number or rows. We do this by getting the num_lines rounded up to X columns
|
||||||
// (num elements is better name) then dividing by columns.
|
// (num elements is better name) then dividing by columns.
|
||||||
state->max_rows = MIN ( state->menu_lines, (unsigned int) ( ( state->num_lines +
|
state->max_rows = MIN ( state->menu_lines, (unsigned int) ( ( state->num_lines + ( state->columns - state->num_lines %
|
||||||
( state->columns - state->num_lines %
|
state->columns ) %
|
||||||
state->columns ) % state->columns ) /
|
state->columns ) / ( state->columns ) ) );
|
||||||
( state->columns ) ) );
|
|
||||||
// Always have at least one row.
|
// Always have at least one row.
|
||||||
state->max_rows = MAX ( 1, state->max_rows );
|
state->max_rows = MAX ( 1, state->max_rows );
|
||||||
|
|
||||||
|
@ -834,18 +833,15 @@ static void menu_update ( MenuState *state )
|
||||||
}
|
}
|
||||||
menu_draw ( state );
|
menu_draw ( state );
|
||||||
// Why do we need the special -1?
|
// Why do we need the special -1?
|
||||||
XDrawLine ( display, main_window, gc, 0,
|
XDrawLine ( display, main_window, gc, 0, state->line_height + ( config.padding ) * 1 + config.line_margin + 1, state->w,
|
||||||
state->line_height + ( config.padding ) * 1 + config.line_margin + 1, state->w,
|
|
||||||
state->line_height + ( config.padding ) * 1 + config.line_margin + 1 );
|
state->line_height + ( config.padding ) * 1 + config.line_margin + 1 );
|
||||||
if ( state->message_tb ) {
|
if ( state->message_tb ) {
|
||||||
XDrawLine ( display, main_window, gc,
|
XDrawLine ( display, main_window, gc, 0, state->top_offset - ( config.line_margin ) - 1,
|
||||||
0, state->top_offset - ( config.line_margin ) - 1,
|
|
||||||
state->w, state->top_offset - ( config.line_margin ) - 1 );
|
state->w, state->top_offset - ( config.line_margin ) - 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config.sidebar_mode == TRUE ) {
|
if ( config.sidebar_mode == TRUE ) {
|
||||||
XDrawLine ( display, main_window, gc,
|
XDrawLine ( display, main_window, gc, 0, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin,
|
||||||
0, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin,
|
|
||||||
state->w, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin );
|
state->w, state->h - state->line_height - ( config.padding ) * 1 - 1 - config.line_margin );
|
||||||
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
||||||
textbox_draw ( switchers[j].tb );
|
textbox_draw ( switchers[j].tb );
|
||||||
|
@ -890,8 +886,7 @@ static void menu_resize ( MenuState *state )
|
||||||
if ( config.sidebar_mode == TRUE ) {
|
if ( config.sidebar_mode == TRUE ) {
|
||||||
int width = ( state->w - ( 2 * ( config.padding ) + ( num_switchers - 1 ) * config.line_margin ) ) / num_switchers;
|
int width = ( state->w - ( 2 * ( config.padding ) + ( num_switchers - 1 ) * config.line_margin ) ) / num_switchers;
|
||||||
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
for ( unsigned int j = 0; j < num_switchers; j++ ) {
|
||||||
textbox_moveresize ( switchers[j].tb,
|
textbox_moveresize ( switchers[j].tb, config.padding + j * ( width + config.line_margin ),
|
||||||
config.padding + j * ( width + config.line_margin ),
|
|
||||||
state->h - state->line_height - config.padding, width, state->line_height );
|
state->h - state->line_height - config.padding, width, state->line_height );
|
||||||
textbox_show ( switchers[j].tb );
|
textbox_show ( switchers[j].tb );
|
||||||
textbox_draw ( switchers[j].tb );
|
textbox_draw ( switchers[j].tb );
|
||||||
|
@ -983,8 +978,7 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
|
|
||||||
// we need this at this point so we can get height.
|
// we need this at this point so we can get height.
|
||||||
state.line_height = textbox_get_estimated_char_height ();
|
state.line_height = textbox_get_estimated_char_height ();
|
||||||
state.case_indicator = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH,
|
state.case_indicator = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
||||||
( config.padding ), ( config.padding ),
|
|
||||||
0, state.line_height, NORMAL, "*" );
|
0, state.line_height, NORMAL, "*" );
|
||||||
// Height of a row.
|
// Height of a row.
|
||||||
if ( config.menu_lines == 0 ) {
|
if ( config.menu_lines == 0 ) {
|
||||||
|
@ -1003,8 +997,7 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select
|
||||||
state.prompt_tb = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
state.prompt_tb = textbox_create ( main_window, &vinfo, map, TB_AUTOWIDTH, ( config.padding ), ( config.padding ),
|
||||||
0, state.line_height, NORMAL, prompt );
|
0, state.line_height, NORMAL, prompt );
|
||||||
// Entry box
|
// Entry box
|
||||||
int entrybox_width = state.w - ( 2 * ( config.padding ) )
|
int entrybox_width = state.w - ( 2 * ( config.padding ) ) - textbox_get_width ( state.prompt_tb )
|
||||||
- textbox_get_width ( state.prompt_tb )
|
|
||||||
- textbox_get_width ( state.case_indicator );
|
- textbox_get_width ( state.case_indicator );
|
||||||
|
|
||||||
state.text = textbox_create ( main_window, &vinfo, map, TB_EDITABLE,
|
state.text = textbox_create ( main_window, &vinfo, map, TB_EDITABLE,
|
||||||
|
@ -1726,8 +1719,7 @@ static int grab_global_keybindings ()
|
||||||
int key_bound = FALSE;
|
int key_bound = FALSE;
|
||||||
for ( unsigned int i = 0; i < num_switchers; i++ ) {
|
for ( unsigned int i = 0; i < num_switchers; i++ ) {
|
||||||
if ( switchers[i].sw->keystr != NULL ) {
|
if ( switchers[i].sw->keystr != NULL ) {
|
||||||
x11_parse_key ( switchers[i].sw->keystr, &( switchers[i].sw->modmask ),
|
x11_parse_key ( switchers[i].sw->keystr, &( switchers[i].sw->modmask ), &( switchers[i].sw->keysym ) );
|
||||||
&( switchers[i].sw->keysym ) );
|
|
||||||
if ( switchers[i].sw->keysym != NoSymbol ) {
|
if ( switchers[i].sw->keysym != NoSymbol ) {
|
||||||
x11_grab_key ( display, switchers[i].sw->modmask, switchers[i].sw->keysym );
|
x11_grab_key ( display, switchers[i].sw->modmask, switchers[i].sw->keysym );
|
||||||
key_bound = TRUE;
|
key_bound = TRUE;
|
||||||
|
@ -2063,8 +2055,7 @@ int main ( int argc, char *argv[] )
|
||||||
fprintf ( stderr, "Please check the manpage on how to specify a key-binding.\n" );
|
fprintf ( stderr, "Please check the manpage on how to specify a key-binding.\n" );
|
||||||
fprintf ( stderr, "The following modi are enabled and keys can be specified:\n" );
|
fprintf ( stderr, "The following modi are enabled and keys can be specified:\n" );
|
||||||
for ( unsigned int i = 0; i < num_switchers; i++ ) {
|
for ( unsigned int i = 0; i < num_switchers; i++ ) {
|
||||||
fprintf ( stderr, "\t* "color_bold "%s"color_reset ": -key-%s <key>\n",
|
fprintf ( stderr, "\t* "color_bold "%s"color_reset ": -key-%s <key>\n", switchers[i].sw->name, switchers[i].sw->name );
|
||||||
switchers[i].sw->name, switchers[i].sw->name );
|
|
||||||
}
|
}
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,16 +56,12 @@ scrollbar *scrollbar_create ( Window parent, XVisualInfo *vinfo, Colormap map,
|
||||||
attr.colormap = map;
|
attr.colormap = map;
|
||||||
attr.border_pixel = color_border ( display );
|
attr.border_pixel = color_border ( display );
|
||||||
attr.background_pixel = color_background ( display );
|
attr.background_pixel = color_background ( display );
|
||||||
sb->window =
|
sb->window = XCreateWindow ( display, sb->parent, sb->x, sb->y, sb->w, sb->h, 0, vinfo->depth, InputOutput, vinfo->visual,
|
||||||
XCreateWindow ( display, sb->parent, sb->x, sb->y, sb->w, sb->h, 0, vinfo->depth,
|
CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
||||||
InputOutput, vinfo->visual, CWColormap |
|
|
||||||
CWBorderPixel | CWBackPixel,
|
|
||||||
&attr );
|
|
||||||
|
|
||||||
XSelectInput ( display, sb->window, ExposureMask | ButtonPressMask | Button1MotionMask );
|
XSelectInput ( display, sb->window, ExposureMask | ButtonPressMask | Button1MotionMask );
|
||||||
sb->gc = XCreateGC ( display, sb->window, 0, 0 );
|
sb->gc = XCreateGC ( display, sb->window, 0, 0 );
|
||||||
XSetForeground ( display, sb->gc, color_separator ( display ) );
|
XSetForeground ( display, sb->gc, color_separator ( display ) );
|
||||||
//XSetFillStyle ( display, sb->gc, FillSolid);
|
|
||||||
|
|
||||||
// Create GC.
|
// Create GC.
|
||||||
return sb;
|
return sb;
|
||||||
|
@ -131,9 +127,7 @@ void scrollbar_draw ( scrollbar *sb )
|
||||||
// Redraw base window
|
// Redraw base window
|
||||||
XClearWindow ( display, sb->window );
|
XClearWindow ( display, sb->window );
|
||||||
// Paint the handle.
|
// Paint the handle.
|
||||||
XFillRectangle ( display, sb->window, sb->gc, config.line_margin, y, sb->w -
|
XFillRectangle ( display, sb->window, sb->gc, config.line_margin, y, sb->w - config.line_margin, height );
|
||||||
config.line_margin,
|
|
||||||
height );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void scrollbar_resize ( scrollbar *sb, int w, int h )
|
void scrollbar_resize ( scrollbar *sb, int w, int h )
|
||||||
|
|
132
source/textbox.c
132
source/textbox.c
|
@ -101,11 +101,8 @@ textbox* textbox_create ( Window parent, XVisualInfo *vinfo, Colormap map, Textb
|
||||||
attr.colormap = map;
|
attr.colormap = map;
|
||||||
attr.border_pixel = cp;
|
attr.border_pixel = cp;
|
||||||
attr.background_pixel = cp;
|
attr.background_pixel = cp;
|
||||||
tb->window =
|
tb->window = XCreateWindow ( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, vinfo->depth,
|
||||||
XCreateWindow ( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, vinfo->depth,
|
InputOutput, vinfo->visual, CWColormap | CWBorderPixel | CWBackPixel, &attr );
|
||||||
InputOutput, vinfo->visual, CWColormap |
|
|
||||||
CWBorderPixel | CWBackPixel,
|
|
||||||
&attr );
|
|
||||||
|
|
||||||
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
|
||||||
pango_layout_set_font_description ( tb->layout, pfd );
|
pango_layout_set_font_description ( tb->layout, pfd );
|
||||||
|
@ -127,10 +124,8 @@ textbox* textbox_create ( Window parent, XVisualInfo *vinfo, Colormap map, Textb
|
||||||
// edit mode controls
|
// edit mode controls
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
if ( tb->flags & TB_EDITABLE ) {
|
||||||
tb->xim = XOpenIM ( display, NULL, NULL, NULL );
|
tb->xim = XOpenIM ( display, NULL, NULL, NULL );
|
||||||
tb->xic =
|
tb->xic = XCreateIC ( tb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
||||||
XCreateIC ( tb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow,
|
tb->window, XNFocusWindow, tb->window, NULL );
|
||||||
tb->window, XNFocusWindow, tb->window,
|
|
||||||
NULL );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XSelectInput ( display, tb->window, ButtonPressMask );
|
XSelectInput ( display, tb->window, ButtonPressMask );
|
||||||
|
@ -343,9 +338,7 @@ void textbox_draw ( textbox *tb )
|
||||||
|
|
||||||
// draw the cursor
|
// draw the cursor
|
||||||
if ( tb->flags & TB_EDITABLE ) {
|
if ( tb->flags & TB_EDITABLE ) {
|
||||||
XftDrawRect ( draw, &tb->color_fg,
|
XftDrawRect ( draw, &tb->color_fg, x / PANGO_SCALE + cursor_x, y / PANGO_SCALE, cursor_width, font_height );
|
||||||
x / PANGO_SCALE + cursor_x, y / PANGO_SCALE, // Align with font
|
|
||||||
cursor_width, font_height );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// flip canvas to window
|
// flip canvas to window
|
||||||
|
@ -389,13 +382,8 @@ static void textbox_cursor_inc_word ( textbox *tb )
|
||||||
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
||||||
gunichar uc = g_utf8_get_char ( c );
|
gunichar uc = g_utf8_get_char ( c );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
if ( (
|
if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
||||||
bt == G_UNICODE_BREAK_ALPHABETIC ||
|
bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) {
|
||||||
bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
|
||||||
bt == G_UNICODE_BREAK_NUMERIC ||
|
|
||||||
bt == G_UNICODE_BREAK_QUOTATION
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,13 +393,8 @@ static void textbox_cursor_inc_word ( textbox *tb )
|
||||||
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
while ( ( c = g_utf8_next_char ( c ) ) ) {
|
||||||
gunichar uc = g_utf8_get_char ( c );
|
gunichar uc = g_utf8_get_char ( c );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
if ( !(
|
if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
||||||
bt == G_UNICODE_BREAK_ALPHABETIC ||
|
bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) {
|
||||||
bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
|
||||||
bt == G_UNICODE_BREAK_NUMERIC ||
|
|
||||||
bt == G_UNICODE_BREAK_QUOTATION
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,13 +410,8 @@ static void textbox_cursor_dec_word ( textbox *tb )
|
||||||
while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) {
|
while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) {
|
||||||
gunichar uc = g_utf8_get_char ( c );
|
gunichar uc = g_utf8_get_char ( c );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
if ( (
|
if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
||||||
bt == G_UNICODE_BREAK_ALPHABETIC ||
|
bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) {
|
||||||
bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
|
||||||
bt == G_UNICODE_BREAK_NUMERIC ||
|
|
||||||
bt == G_UNICODE_BREAK_QUOTATION
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -441,13 +419,8 @@ static void textbox_cursor_dec_word ( textbox *tb )
|
||||||
while ( ( n = g_utf8_prev_char ( c ) ) ) {
|
while ( ( n = g_utf8_prev_char ( c ) ) ) {
|
||||||
gunichar uc = g_utf8_get_char ( n );
|
gunichar uc = g_utf8_get_char ( n );
|
||||||
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
GUnicodeBreakType bt = g_unichar_break_type ( uc );
|
||||||
if ( !(
|
if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
||||||
bt == G_UNICODE_BREAK_ALPHABETIC ||
|
bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) {
|
||||||
bt == G_UNICODE_BREAK_HEBREW_LETTER ||
|
|
||||||
bt == G_UNICODE_BREAK_NUMERIC ||
|
|
||||||
bt == G_UNICODE_BREAK_QUOTATION
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
c = n;
|
c = n;
|
||||||
|
@ -684,9 +657,7 @@ static void textbox_parse_string ( XVisualInfo *visual, Colormap colormap, const
|
||||||
char *endp;
|
char *endp;
|
||||||
char *token;
|
char *token;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for ( token =
|
for ( token = strtok_r ( cstr, ",", &endp ); token != NULL; token = strtok_r ( NULL, ",", &endp ) ) {
|
||||||
strtok_r ( cstr, ",",
|
|
||||||
&endp ); token != NULL; token = strtok_r ( NULL, ",", &endp ) ) {
|
|
||||||
switch ( index )
|
switch ( index )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -696,8 +667,7 @@ static void textbox_parse_string ( XVisualInfo *visual, Colormap colormap, const
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->fg ), "white" );
|
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->fg ), "white" );
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip (
|
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->bgalt ), "black" );
|
||||||
token ), &( color->bgalt ), "black" );
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->hlbg ), "black" );
|
parse_color ( visual->visual, colormap, g_strstrip ( token ), &( color->hlbg ), "black" );
|
||||||
|
@ -716,46 +686,28 @@ void textbox_setup ( XVisualInfo *visual, Colormap colormap )
|
||||||
target_colormap = colormap;
|
target_colormap = colormap;
|
||||||
|
|
||||||
if ( config.color_enabled ) {
|
if ( config.color_enabled ) {
|
||||||
textbox_parse_string ( visual, target_colormap,
|
textbox_parse_string ( visual, target_colormap, config.color_normal, &( colors[NORMAL] ) );
|
||||||
config.color_normal, &( colors[NORMAL] ) );
|
textbox_parse_string ( visual, target_colormap, config.color_urgent, &( colors[URGENT] ) );
|
||||||
textbox_parse_string ( visual, target_colormap,
|
textbox_parse_string ( visual, target_colormap, config.color_active, &( colors[ACTIVE] ) );
|
||||||
config.color_urgent, &( colors[URGENT] ) );
|
|
||||||
textbox_parse_string ( visual, target_colormap,
|
|
||||||
config.color_active, &( colors[ACTIVE] ) );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg, &( colors[NORMAL].bg ),
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg, &( colors[NORMAL].bg ), "black" );
|
||||||
"black" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_fg, &( colors[NORMAL].fg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg, &( colors[NORMAL].fg ),
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[NORMAL].bgalt ), "black" );
|
||||||
"white" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg, &( colors[NORMAL].hlfg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt,
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg, &( colors[NORMAL].hlbg ), "black" );
|
||||||
&( colors[NORMAL].bgalt ), "black" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg,
|
|
||||||
&( colors[NORMAL].hlfg ), "white" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg,
|
|
||||||
&( colors[NORMAL].hlbg ), "black" );
|
|
||||||
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_urgent,
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg_urgent, &( colors[URGENT].bg ), "black" );
|
||||||
&( colors[URGENT].bg ), "black" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_fg_urgent, &( colors[URGENT].fg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg_urgent,
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[URGENT].bgalt ), "black" );
|
||||||
&( colors[URGENT].fg ), "white" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_urgent, &( colors[URGENT].hlfg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt,
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_urgent, &( colors[URGENT].hlbg ), "black" );
|
||||||
&( colors[URGENT].bgalt ), "black" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_urgent,
|
|
||||||
&( colors[URGENT].hlfg ), "white" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_urgent,
|
|
||||||
&( colors[URGENT].hlbg ), "black" );
|
|
||||||
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_active,
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg_active, &( colors[ACTIVE].bg ), "black" );
|
||||||
&( colors[ACTIVE].bg ), "black" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_fg_active, &( colors[ACTIVE].fg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_fg_active,
|
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt, &( colors[ACTIVE].bgalt ), "black" );
|
||||||
&( colors[ACTIVE].fg ), "white" );
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_active, &( colors[ACTIVE].hlfg ), "white" );
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_bg_alt,
|
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_active, &( colors[ACTIVE].hlbg ), "black" );
|
||||||
&( colors[ACTIVE].bgalt ), "black" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlfg_active,
|
|
||||||
&( colors[ACTIVE].hlfg ), "white" );
|
|
||||||
parse_color ( visual_info->visual, target_colormap, config.menu_hlbg_active,
|
|
||||||
&( colors[ACTIVE].hlbg ), "black" );
|
|
||||||
}
|
}
|
||||||
PangoFontMap *font_map = pango_xft_get_font_map ( display, DefaultScreen ( display ) );
|
PangoFontMap *font_map = pango_xft_get_font_map ( display, DefaultScreen ( display ) );
|
||||||
p_context = pango_font_map_create_context ( font_map );
|
p_context = pango_font_map_create_context ( font_map );
|
||||||
|
@ -763,16 +715,11 @@ void textbox_setup ( XVisualInfo *visual, Colormap colormap )
|
||||||
|
|
||||||
static void textbox_clean_rowcolor ( RowColor * color )
|
static void textbox_clean_rowcolor ( RowColor * color )
|
||||||
{
|
{
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap,
|
XftColorFree ( display, visual_info->visual, target_colormap, &( color->fg ) );
|
||||||
&( color->fg ) );
|
XftColorFree ( display, visual_info->visual, target_colormap, &( color->bg ) );
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap,
|
XftColorFree ( display, visual_info->visual, target_colormap, &( color->bgalt ) );
|
||||||
&( color->bg ) );
|
XftColorFree ( display, visual_info->visual, target_colormap, &( color->hlfg ) );
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap,
|
XftColorFree ( display, visual_info->visual, target_colormap, &( color->hlbg ) );
|
||||||
&( color->bgalt ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap,
|
|
||||||
&( color->hlfg ) );
|
|
||||||
XftColorFree ( display, visual_info->visual, target_colormap,
|
|
||||||
&( color->hlbg ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void textbox_cleanup ( void )
|
void textbox_cleanup ( void )
|
||||||
|
@ -840,8 +787,7 @@ int textbox_get_estimated_char_height ( void )
|
||||||
|
|
||||||
// Get width
|
// Get width
|
||||||
PangoFontMetrics *metric = pango_context_get_metrics ( p_context, pfd, NULL );
|
PangoFontMetrics *metric = pango_context_get_metrics ( p_context, pfd, NULL );
|
||||||
int height = pango_font_metrics_get_ascent ( metric ) +
|
int height = pango_font_metrics_get_ascent ( metric ) + pango_font_metrics_get_descent ( metric );
|
||||||
pango_font_metrics_get_descent ( metric );
|
|
||||||
pango_font_metrics_unref ( metric );
|
pango_font_metrics_unref ( metric );
|
||||||
|
|
||||||
pango_font_description_free ( pfd );
|
pango_font_description_free ( pfd );
|
||||||
|
|
|
@ -66,8 +66,8 @@ int window_get_prop ( Display *display, Window w, Atom prop, Atom *type, int *it
|
||||||
unsigned char *ret = NULL;
|
unsigned char *ret = NULL;
|
||||||
memset ( buffer, 0, bytes );
|
memset ( buffer, 0, bytes );
|
||||||
|
|
||||||
if ( XGetWindowProperty ( display, w, prop, 0, bytes / 4, False, AnyPropertyType, type, &format, &nitems, &nbytes,
|
if ( XGetWindowProperty ( display, w, prop, 0, bytes / 4, False, AnyPropertyType, type, &format, &nitems, &nbytes, &ret ) == Success &&
|
||||||
&ret ) == Success && ret && *type != None && format ) {
|
ret && *type != None && format ) {
|
||||||
if ( format == 8 ) {
|
if ( format == 8 ) {
|
||||||
memmove ( buffer, ret, MIN ( bytes, nitems ) );
|
memmove ( buffer, ret, MIN ( bytes, nitems ) );
|
||||||
}
|
}
|
||||||
|
@ -233,8 +233,8 @@ void monitor_active ( Display *display, workarea *mon )
|
||||||
}
|
}
|
||||||
fprintf ( stderr, "Failed to find selected monitor.\n" );
|
fprintf ( stderr, "Failed to find selected monitor.\n" );
|
||||||
}
|
}
|
||||||
if ( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, &count, &id, sizeof ( Window ) )
|
if ( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, &count, &id, sizeof ( Window ) )
|
||||||
&& type == XA_WINDOW && count > 0 ) {
|
&& type == XA_WINDOW && count > 0 ) {
|
||||||
XWindowAttributes attr;
|
XWindowAttributes attr;
|
||||||
if ( XGetWindowAttributes ( display, id, &attr ) ) {
|
if ( XGetWindowAttributes ( display, id, &attr ) ) {
|
||||||
Window junkwin;
|
Window junkwin;
|
||||||
|
@ -444,9 +444,8 @@ static int ( *xerror )( Display *, XErrorEvent * );
|
||||||
*/
|
*/
|
||||||
static int display_oops ( Display *d, XErrorEvent *ee )
|
static int display_oops ( Display *d, XErrorEvent *ee )
|
||||||
{
|
{
|
||||||
if ( ee->error_code == BadWindow
|
if ( ee->error_code == BadWindow || ( ee->request_code == X_GrabButton && ee->error_code == BadAccess )
|
||||||
|| ( ee->request_code == X_GrabButton && ee->error_code == BadAccess )
|
|| ( ee->request_code == X_GrabKey && ee->error_code == BadAccess ) ) {
|
||||||
|| ( ee->request_code == X_GrabKey && ee->error_code == BadAccess )) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +474,7 @@ void create_visual_and_colormap ( Display *display )
|
||||||
// Try to create TrueColor map
|
// Try to create TrueColor map
|
||||||
if ( XMatchVisualInfo ( display, screen, 32, TrueColor, &vinfo ) ) {
|
if ( XMatchVisualInfo ( display, screen, 32, TrueColor, &vinfo ) ) {
|
||||||
// Visual found, lets try to create map.
|
// Visual found, lets try to create map.
|
||||||
map = XCreateColormap ( display, DefaultRootWindow ( display ), vinfo.visual, AllocNone );
|
map = XCreateColormap ( display, DefaultRootWindow ( display ), vinfo.visual, AllocNone );
|
||||||
truecolor = TRUE;
|
truecolor = TRUE;
|
||||||
}
|
}
|
||||||
// Failed to create map.
|
// Failed to create map.
|
||||||
|
|
|
@ -53,146 +53,82 @@ typedef struct
|
||||||
* Currently supports string, boolean and number (signed and unsigned).
|
* Currently supports string, boolean and number (signed and unsigned).
|
||||||
*/
|
*/
|
||||||
static XrmOption xrmOptions[] = {
|
static XrmOption xrmOptions[] = {
|
||||||
{ xrm_String, "switchers",
|
{ xrm_String, "switchers", { .str = &config.switchers }, NULL },
|
||||||
{ .str = &config.switchers },
|
{ xrm_String, "modi", { .str = &config.switchers }, NULL },
|
||||||
NULL },
|
{ xrm_Number, "opacity", { .num = &config.window_opacity }, NULL },
|
||||||
{ xrm_String, "modi", { .str = &config.switchers },
|
{ xrm_SNumber, "width", { .snum = &config.menu_width }, NULL },
|
||||||
NULL },
|
{ xrm_Number, "lines", { .num = &config.menu_lines }, NULL },
|
||||||
{ xrm_Number, "opacity", { .num = &config.window_opacity },
|
{ xrm_Number, "columns", { .num = &config.menu_columns }, NULL },
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_SNumber, "width", { .snum = &config.menu_width },
|
{ xrm_String, "font", { .str = &config.menu_font }, NULL },
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Number, "lines", { .num = &config.menu_lines },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Number, "columns", { .num = &config.menu_columns },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "font", { .str = &config.menu_font },
|
|
||||||
NULL },
|
|
||||||
/* Foreground color */
|
/* Foreground color */
|
||||||
{ xrm_String, "foreground", { .str = &config.menu_fg },
|
{ xrm_String, "foreground", { .str = &config.menu_fg }, NULL },
|
||||||
NULL },
|
{ xrm_String, "fg", { .str = &config.menu_fg }, NULL },
|
||||||
{ xrm_String, "fg", { .str = &config.menu_fg },
|
{ xrm_String, "background", { .str = &config.menu_bg }, NULL },
|
||||||
NULL },
|
{ xrm_String, "bg", { .str = &config.menu_bg }, NULL },
|
||||||
{ xrm_String, "background", { .str = &config.menu_bg },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "bg", { .str = &config.menu_bg },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Boolean, "color-enabled", { .num = &config.color_enabled },
|
{ xrm_Boolean, "color-enabled", { .num = &config.color_enabled }, NULL },
|
||||||
NULL },
|
{ xrm_String, "color-normal", { .str = &config.color_normal }, NULL },
|
||||||
{ xrm_String, "color-normal", { .str = &config.color_normal },
|
{ xrm_String, "color-urgent", { .str = &config.color_urgent }, NULL },
|
||||||
NULL },
|
{ xrm_String, "color-active", { .str = &config.color_active }, NULL },
|
||||||
{ xrm_String, "color-urgent", { .str = &config.color_urgent },
|
{ xrm_String, "color-window", { .str = &config.color_window }, NULL },
|
||||||
NULL },
|
|
||||||
{ xrm_String, "color-active", { .str = &config.color_active },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "color-window", { .str = &config.color_window },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "fg-active", { .str = &config.menu_fg_active },
|
{ xrm_String, "fg-active", { .str = &config.menu_fg_active }, NULL },
|
||||||
NULL },
|
{ xrm_String, "fg-urgent", { .str = &config.menu_fg_urgent }, NULL },
|
||||||
{ xrm_String, "fg-urgent", { .str = &config.menu_fg_urgent },
|
{ xrm_String, "hlfg-active", { .str = &config.menu_hlfg_active }, NULL },
|
||||||
NULL },
|
{ xrm_String, "hlfg-urgent", { .str = &config.menu_hlfg_urgent }, NULL },
|
||||||
{ xrm_String, "hlfg-active", { .str = &config.menu_hlfg_active },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "hlfg-urgent", { .str = &config.menu_hlfg_urgent },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "bg-active", { .str = &config.menu_bg_active },
|
{ xrm_String, "bg-active", { .str = &config.menu_bg_active }, NULL },
|
||||||
NULL },
|
{ xrm_String, "bg-urgent", { .str = &config.menu_bg_urgent }, NULL },
|
||||||
{ xrm_String, "bg-urgent", { .str = &config.menu_bg_urgent },
|
{ xrm_String, "hlbg-active", { .str = &config.menu_hlbg_active }, NULL },
|
||||||
NULL },
|
{ xrm_String, "hlbg-urgent", { .str = &config.menu_hlbg_urgent }, NULL },
|
||||||
{ xrm_String, "hlbg-active", { .str = &config.menu_hlbg_active },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "hlbg-urgent", { .str = &config.menu_hlbg_urgent },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "background-alternate", { .str = &config.menu_bg_alt },
|
{ xrm_String, "background-alternate", { .str = &config.menu_bg_alt }, NULL },
|
||||||
NULL },
|
{ xrm_String, "bgalt", { .str = &config.menu_bg_alt }, NULL },
|
||||||
{ xrm_String, "bgalt", { .str = &config.menu_bg_alt },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "highlightfg", { .str = &config.menu_hlfg },
|
{ xrm_String, "highlightfg", { .str = &config.menu_hlfg }, NULL },
|
||||||
NULL },
|
{ xrm_String, "hlfg", { .str = &config.menu_hlfg }, NULL },
|
||||||
{ xrm_String, "hlfg", { .str = &config.menu_hlfg },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "highlightbg", { .str = &config.menu_hlbg },
|
{ xrm_String, "highlightbg", { .str = &config.menu_hlbg }, NULL },
|
||||||
NULL },
|
{ xrm_String, "hlbg", { .str = &config.menu_hlbg }, NULL },
|
||||||
{ xrm_String, "hlbg", { .str = &config.menu_hlbg },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "bordercolor", { .str = &config.menu_bc },
|
{ xrm_String, "bordercolor", { .str = &config.menu_bc }, NULL },
|
||||||
NULL },
|
{ xrm_String, "bc", { .str = &config.menu_bc }, NULL },
|
||||||
{ xrm_String, "bc", { .str = &config.menu_bc },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Number, "borderwidth", { .num = &config.menu_bw },
|
{ xrm_Number, "borderwidth", { .num = &config.menu_bw }, NULL },
|
||||||
NULL },
|
{ xrm_Number, "bw", { .num = &config.menu_bw }, NULL },
|
||||||
{ xrm_Number, "bw", { .num = &config.menu_bw },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Number, "location", { .num = &config.location },
|
{ xrm_Number, "location", { .num = &config.location }, NULL },
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Number, "padding", { .num = &config.padding },
|
{ xrm_Number, "padding", { .num = &config.padding }, NULL },
|
||||||
NULL },
|
{ xrm_SNumber, "yoffset", { .snum = &config.y_offset }, NULL },
|
||||||
{ xrm_SNumber, "yoffset", { .snum = &config.y_offset },
|
{ xrm_SNumber, "xoffset", { .snum = &config.x_offset }, NULL },
|
||||||
NULL },
|
{ xrm_Boolean, "fixed-num-lines", { .num = &config.fixed_num_lines }, NULL },
|
||||||
{ xrm_SNumber, "xoffset", { .snum = &config.x_offset },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Boolean, "fixed-num-lines", { .num = &config.fixed_num_lines },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_String, "terminal", { .str = &config.terminal_emulator },
|
{ xrm_String, "terminal", { .str = &config.terminal_emulator }, NULL },
|
||||||
NULL },
|
{ xrm_String, "ssh-client", { .str = &config.ssh_client }, NULL },
|
||||||
{ xrm_String, "ssh-client", { .str = &config.ssh_client },
|
{ xrm_String, "ssh-command", { .str = &config.ssh_command }, NULL },
|
||||||
NULL },
|
{ xrm_String, "run-command", { .str = &config.run_command }, NULL },
|
||||||
{ xrm_String, "ssh-command", { .str = &config.ssh_command },
|
{ xrm_String, "run-list-command", { .str = &config.run_list_command }, NULL },
|
||||||
NULL },
|
{ xrm_String, "run-shell-command", { .str = &config.run_shell_command }, NULL },
|
||||||
{ xrm_String, "run-command", { .str = &config.run_command },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "run-list-command", { .str = &config.run_list_command },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "run-shell-command", { .str = &config.run_shell_command },
|
|
||||||
NULL },
|
|
||||||
|
|
||||||
{ xrm_Boolean, "disable-history", { .num = &config.disable_history },
|
{ xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL },
|
||||||
NULL },
|
{ xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort }, NULL },
|
||||||
{ xrm_Boolean, "levenshtein-sort", { .num = &config.levenshtein_sort },
|
{ xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive }, NULL },
|
||||||
NULL },
|
{ xrm_Boolean, "sidebar-mode", { .num = &config.sidebar_mode }, NULL },
|
||||||
{ xrm_Boolean, "case-sensitive", { .num = &config.case_sensitive },
|
{ xrm_Number, "lazy-filter-limit", { .num = &config.lazy_filter_limit }, NULL },
|
||||||
NULL },
|
{ xrm_SNumber, "eh", { .snum = &config.element_height }, NULL },
|
||||||
{ xrm_Boolean, "sidebar-mode", { .num = &config.sidebar_mode },
|
{ xrm_Boolean, "auto-select", { .num = &config.auto_select }, NULL },
|
||||||
NULL },
|
{ xrm_Boolean, "parse-hosts", { .num = &config.parse_hosts }, NULL },
|
||||||
{ xrm_Number, "lazy-filter-limit", { .num = &config.lazy_filter_limit },
|
{ xrm_String, "combi-modi", { .str = &config.combi_modi }, NULL },
|
||||||
NULL },
|
{ xrm_Boolean, "fuzzy", { .num = &config.fuzzy }, NULL },
|
||||||
{ xrm_SNumber, "eh", { .snum = &config.element_height },
|
{ xrm_Number, "monitor", { .snum = &config.monitor }, NULL },
|
||||||
NULL },
|
|
||||||
{ xrm_Boolean, "auto-select", { .num = &config.auto_select },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Boolean, "parse-hosts", { .num = &config.parse_hosts },
|
|
||||||
NULL },
|
|
||||||
{ xrm_String, "combi-modi", { .str = &config.combi_modi },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Boolean, "fuzzy", { .num = &config.fuzzy },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Number, "monitor", { .snum = &config.monitor },
|
|
||||||
NULL },
|
|
||||||
/* Alias for dmenu compatibility. */
|
/* Alias for dmenu compatibility. */
|
||||||
{ xrm_SNumber, "m", { .snum = &config.monitor },
|
{ xrm_SNumber, "m", { .snum = &config.monitor }, NULL },
|
||||||
NULL },
|
{ xrm_Number, "line-margin", { .num = &config.line_margin }, NULL },
|
||||||
{ xrm_Number, "line-margin", { .num = &config.line_margin },
|
{ xrm_String, "filter", { .str = &config.filter }, NULL },
|
||||||
NULL },
|
{ xrm_String, "separator-style", { .str = &config.separator_style }, NULL },
|
||||||
{ xrm_String, "filter", { .str = &config.filter },
|
{ xrm_Boolean, "hide-scrollbar", { .num = &config.hide_scrollbar }, NULL }
|
||||||
NULL },
|
|
||||||
{ xrm_String, "separator-style", { .str = &config.separator_style },
|
|
||||||
NULL },
|
|
||||||
{ xrm_Boolean, "hide-scrollbar", { .num = &config.hide_scrollbar },
|
|
||||||
NULL }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dynamic options.
|
// Dynamic options.
|
||||||
|
|
Loading…
Reference in a new issue