Indent o mania.

This commit is contained in:
QC 2014-03-22 21:04:19 +01:00
parent 4d37cf35dc
commit c87312be36
10 changed files with 1906 additions and 1328 deletions

View File

@ -30,41 +30,41 @@ Settings config = {
// Set the default window opacity.
// This option only works when running a composite manager.
// -o
.window_opacity = 100,
.window_opacity = 100,
// Border width around the window.
.menu_bw = 1,
.menu_bw = 1,
// The width of the switcher. (0-100 in % > 100 in pixels)
.menu_width = 50,
.menu_width = 50,
// Maximum number of options to show.
.menu_lines = 15,
.menu_lines = 15,
// Font
.menu_font = "mono-12",
.menu_font = "mono-12",
// Foreground color
.menu_fg = "#222222",
.menu_fg = "#222222",
// Background color
.menu_bg = "#f2f1f0",
.menu_bg = "#f2f1f0",
// Foreground color (selected)
.menu_hlfg = "#ffffff",
.menu_hlfg = "#ffffff",
// Background color (selected)
.menu_hlbg = "#005577",
.menu_hlbg = "#005577",
// Border color.
.menu_bc = "black",
.menu_bc = "black",
// Directly select when only 1 choice is left
.zeltak_mode = 0,
.zeltak_mode = 0,
// Terminal to use. (for ssh and open in terminal)
.terminal_emulator = "x-terminal-emulator",
#ifdef I3
// Auto-detected. no longer used.
.i3_mode = 0,
.i3_mode = 0,
#endif
// Key binding
.window_key = "F12",
.run_key = "mod1+F2",
.ssh_key = "mod1+F3",
.window_key = "F12",
.run_key = "mod1+F2",
.ssh_key = "mod1+F3",
// Location of the window. WL_CENTER, WL_NORTH_WEST, WL_NORTH,WL_NORTH_EAST, etc.
.location = WL_CENTER,
.location = WL_CENTER,
// Mode of window, list (Vertical) or dmenu like (Horizontal)
.wmode = VERTICAL,
.wmode = VERTICAL,
// Padding of the window.
.padding = 5
.padding = 5
};

View File

@ -3,18 +3,19 @@
#include <config.h>
#include <X11/X.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define NEAR(a,o,b) ((b) > (a)-(o) && (b) < (a)+(o))
#define OVERLAP(a,b,c,d) (((a)==(c) && (b)==(d)) || MIN((a)+(b), (c)+(d)) - MAX((a), (c)) > 0)
#define INTERSECT(x,y,w,h,x1,y1,w1,h1) (OVERLAP((x),(w),(x1),(w1)) && OVERLAP((y),(h),(y1),(h1)))
#define MAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
#define MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
#define NEAR( a, o, b ) ( ( b ) > ( a ) - ( o ) && ( b ) < ( a ) + ( o ) )
#define OVERLAP( a, b, c, d ) ( ( ( a ) == ( c ) && ( b ) == ( d ) ) || MIN ( ( a ) + ( b ), ( c ) + ( d ) ) - MAX ( ( a ), ( c ) ) > 0 )
#define INTERSECT( x, y, w, h, x1, y1, w1, h1 ) ( OVERLAP ( ( x ), ( w ), ( x1 ), ( w1 ) ) && OVERLAP ( ( y ), ( h ), ( y1 ), ( h1 ) ) )
extern const char *cache_dir;
#ifdef HAVE_I3_IPC_H
extern char *i3_socket_path;
extern char *i3_socket_path;
#endif
typedef enum {
typedef enum
{
WINDOW_SWITCHER,
RUN_DIALOG,
SSH_DIALOG,
@ -24,46 +25,48 @@ typedef enum {
NEXT_DIALOG
} SwitcherMode;
typedef enum {
MENU_OK = 0,
typedef enum
{
MENU_OK = 0,
MENU_CANCEL = -1,
MENU_NEXT = -2,
MENU_CUSTOM_INPUT = -3,
MENU_ENTRY_DELETE = -4
} MenuReturn;
typedef int ( *menu_match_cb )( char **tokens, const char *input, int index, void *data );
MenuReturn menu( char **lines, char **input, char *prompt,
Time *time, int *shift,
menu_match_cb mmc, void *mmc_data,
int *selected_line );
MenuReturn menu ( char **lines, char **input, char *prompt,
Time *time, int *shift,
menu_match_cb mmc, void *mmc_data,
int *selected_line );
/**
* Allocator wrappers
*/
void* allocate( unsigned long bytes ) __attribute__((malloc));
void* allocate_clear( unsigned long bytes );
void* reallocate( void *ptr, unsigned long bytes );
void* allocate ( unsigned long bytes ) __attribute__( ( malloc ) );
void* allocate_clear ( unsigned long bytes );
void* reallocate ( void *ptr, unsigned long bytes );
void catch_exit( __attribute__( ( unused ) ) int sig );
void catch_exit ( __attribute__( ( unused ) ) int sig );
typedef enum _WindowLocation {
WL_CENTER = 0,
WL_NORTH_WEST = 1,
WL_NORTH = 2,
WL_NORTH_EAST = 3,
WL_EAST = 4,
WL_EAST_SOUTH = 5,
WL_SOUTH = 6,
WL_SOUTH_WEST = 7,
WL_WEST = 8
typedef enum _WindowLocation
{
WL_CENTER = 0,
WL_NORTH_WEST = 1,
WL_NORTH = 2,
WL_NORTH_EAST = 3,
WL_EAST = 4,
WL_EAST_SOUTH = 5,
WL_SOUTH = 6,
WL_SOUTH_WEST = 7,
WL_WEST = 8
} WindowLocation;
typedef enum {
typedef enum
{
VERTICAL = 0,
HORIZONTAL = 1
} WindowMode;
@ -71,38 +74,39 @@ typedef enum {
* Settings
*/
typedef struct _Settings {
typedef struct _Settings
{
// Window settings
unsigned int window_opacity;
unsigned int window_opacity;
// Menu settings
unsigned int menu_bw;
unsigned int menu_width;
unsigned int menu_lines;
char * menu_font;
char * menu_fg;
char * menu_bg;
char * menu_hlfg;
char * menu_hlbg;
char * menu_bc;
unsigned int menu_bw;
unsigned int menu_width;
unsigned int menu_lines;
char * menu_font;
char * menu_fg;
char * menu_bg;
char * menu_hlfg;
char * menu_hlbg;
char * menu_bc;
// Behavior
unsigned int zeltak_mode;
char * terminal_emulator;
unsigned int zeltak_mode;
char * terminal_emulator;
#ifdef HAVE_I3_IPC_H
unsigned int i3_mode;
unsigned int i3_mode;
#endif
// Key bindings
char * window_key;
char * run_key;
char * ssh_key;
WindowLocation location;
WindowMode wmode;
unsigned int padding;
char * window_key;
char * run_key;
char * ssh_key;
WindowLocation location;
WindowMode wmode;
unsigned int padding;
} Settings;
extern Settings config;
int token_match ( char **tokens, const char *input,
__attribute__( ( unused ) )int index,
__attribute__( ( unused ) )void *data );
__attribute__( ( unused ) ) int index,
__attribute__( ( unused ) ) void *data );
#endif

View File

@ -1,47 +1,49 @@
#ifndef __TEXTBOX_H__
#define __TEXTBOX_H__
typedef struct {
typedef struct
{
unsigned long flags;
Window window, parent;
short x, y, w, h;
short cursor;
XftFont *font;
XftColor color_fg, color_bg;
char *text, *prompt;
XIM xim;
XIC xic;
XGlyphInfo extents;
Window window, parent;
short x, y, w, h;
short cursor;
XftFont *font;
XftColor color_fg, color_bg;
char *text, *prompt;
XIM xim;
XIC xic;
XGlyphInfo extents;
} textbox;
typedef enum {
TB_AUTOHEIGHT = 1<<0,
TB_AUTOWIDTH = 1<<1,
TB_LEFT = 1<<16,
TB_RIGHT = 1<<17,
TB_CENTER = 1<<18,
TB_EDITABLE = 1<<19,
typedef enum
{
TB_AUTOHEIGHT = 1 << 0,
TB_AUTOWIDTH = 1 << 1,
TB_LEFT = 1 << 16,
TB_RIGHT = 1 << 17,
TB_CENTER = 1 << 18,
TB_EDITABLE = 1 << 19,
} TextboxFlags;
textbox* textbox_create( Window parent,
TextboxFlags flags,
short x, short y, short w, short h,
char *font, char *fg, char *bg,
char *text, char *prompt );
textbox* textbox_create ( Window parent,
TextboxFlags flags,
short x, short y, short w, short h,
char *font, char *fg, char *bg,
char *text, char *prompt );
void textbox_free( textbox *tb );
void textbox_free ( textbox *tb );
void textbox_font( textbox *tb, char *font, char *fg, char *bg );
void textbox_font ( textbox *tb, char *font, char *fg, char *bg );
void textbox_text( textbox *tb, char *text );
void textbox_show( textbox *tb );
void textbox_draw( textbox *tb );
void textbox_text ( textbox *tb, char *text );
void textbox_show ( textbox *tb );
void textbox_draw ( textbox *tb );
int textbox_keypress( textbox *tb, XEvent *ev );
int textbox_keypress ( textbox *tb, XEvent *ev );
void textbox_cursor_end( textbox *tb );
void textbox_cursor_end ( textbox *tb );
#endif //__TEXTBOX_H__

View File

@ -1,5 +1,5 @@
#ifndef __XRMOPTIONS_H__
#define __XRMOPTIONS_H__
void parse_xresource_options( Display *display );
void parse_xresource_options ( Display *display );
#endif

View File

@ -42,16 +42,19 @@ static char **get_dmenu ( )
{
char buffer[1024];
char **retv = NULL;
int index = 0;
int index = 0;
while ( fgets( buffer, 1024, stdin ) != NULL ) {
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
retv[index] = strdup( buffer );
retv[index+1] = NULL;
while ( fgets ( buffer, 1024, stdin ) != NULL )
{
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
retv[index] = strdup ( buffer );
retv[index + 1] = NULL;
// Filter out line-end.
if ( retv[index][strlen( buffer )-1] == '\n' )
retv[index][strlen( buffer )-1] = '\0';
if ( retv[index][strlen ( buffer ) - 1] == '\n' )
{
retv[index][strlen ( buffer ) - 1] = '\0';
}
index++;
}
@ -61,27 +64,36 @@ static char **get_dmenu ( )
SwitcherMode dmenu_switcher_dialog ( char **input )
{
int selected_line = 0;
SwitcherMode retv = MODE_EXIT;
int selected_line = 0;
SwitcherMode retv = MODE_EXIT;
// act as a launcher
char **list = get_dmenu( );
char **list = get_dmenu ( );
int mretv = menu( list, input, dmenu_prompt,NULL, NULL,
token_match, NULL, &selected_line );
int mretv = menu ( list, input, dmenu_prompt, NULL, NULL,
token_match, NULL, &selected_line );
if ( mretv == MENU_NEXT ) {
if ( mretv == MENU_NEXT )
{
retv = DMENU_DIALOG;
} else if ( mretv == MENU_OK && list[selected_line] != NULL ) {
fputs( list[selected_line],stdout );
} else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) {
fputs( *input, stdout );
}
else if ( mretv == MENU_OK && list[selected_line] != NULL )
{
fputs ( list[selected_line], stdout );
}
else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' )
{
fputs ( *input, stdout );
}
for ( unsigned int i=0; list != NULL && list[i] != NULL; i++ ) {
free( list[i] );
for ( unsigned int i = 0; list != NULL && list[i] != NULL; i++ )
{
free ( list[i] );
}
if ( list != NULL ) free( list );
if ( list != NULL )
{
free ( list );
}
return retv;
}

File diff suppressed because it is too large Load Diff

View File

@ -45,151 +45,176 @@
#include <time.h>
#endif
#define RUN_CACHE_FILE "rofi-2.runcache"
#define RUN_CACHE_FILE "rofi-2.runcache"
static inline int execsh( const char *cmd ,int run_in_term )
static inline int execsh ( const char *cmd, int run_in_term )
{
// use sh for args parsing
if ( run_in_term )
return execlp( config.terminal_emulator, config.terminal_emulator, "-e", "sh", "-c", cmd, NULL );
{
return execlp ( config.terminal_emulator, config.terminal_emulator, "-e", "sh", "-c", cmd, NULL );
}
return execlp( "/bin/sh", "sh", "-c", cmd, NULL );
return execlp ( "/bin/sh", "sh", "-c", cmd, NULL );
}
typedef struct _element{
long int index;
char name[1024];
}element;
static int element_sort_func(const void *ea,const void *eb)
typedef struct _element
{
element *a = *(element **)ea;
element *b = *(element **)eb;
long int index;
char name[1024];
}element;
static int element_sort_func ( const void *ea, const void *eb )
{
element *a = *(element * *) ea;
element *b = *(element * *) eb;
return b->index - a->index;
}
// execute sub-process
static pid_t exec_cmd( const char *cmd, int run_in_term )
static pid_t exec_cmd ( const char *cmd, int run_in_term )
{
if ( !cmd || !cmd[0] ) return -1;
signal( SIGCHLD, catch_exit );
pid_t pid = fork();
if ( !pid ) {
setsid();
execsh( cmd, run_in_term );
exit( EXIT_FAILURE );
if ( !cmd || !cmd[0] )
{
return -1;
}
int curr = -1;
unsigned int index = 0;
element **retv = NULL;
signal ( SIGCHLD, catch_exit );
pid_t pid = fork ();
if ( !pid )
{
setsid ();
execsh ( cmd, run_in_term );
exit ( EXIT_FAILURE );
}
int curr = -1;
unsigned int index = 0;
element **retv = NULL;
/**
* This happens in non-critical time (After launching app)
* It is allowed to be a bit slower.
*/
size_t path_length = strlen( cache_dir ) + strlen( RUN_CACHE_FILE )+3;
char *path = allocate( path_length );
snprintf( path, path_length, "%s/%s", cache_dir, RUN_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
size_t path_length = strlen ( cache_dir ) + strlen ( RUN_CACHE_FILE ) + 3;
char *path = allocate ( path_length );
snprintf ( path, path_length, "%s/%s", cache_dir, RUN_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
if ( fd != NULL ) {
if ( fd != NULL )
{
char buffer[1024];
while ( fgets( buffer,1024,fd ) != NULL ) {
if(strlen(buffer) == 0) continue;
retv = reallocate( retv, ( index+2 )*sizeof( element* ) );
retv[index] = allocate(sizeof(element));
buffer[strlen( buffer )-1] = '\0';
while ( fgets ( buffer, 1024, fd ) != NULL )
{
if ( strlen ( buffer ) == 0 )
{
continue;
}
retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) );
retv[index] = allocate ( sizeof ( element ) );
buffer[strlen ( buffer ) - 1] = '\0';
char * start = NULL;
retv[index]->index = strtol(buffer, &start, 10);
snprintf(retv[index]->name, 1024, "%s", start+1);
retv[index+1] = NULL;
retv[index]->index = strtol ( buffer, &start, 10 );
snprintf ( retv[index]->name, 1024, "%s", start + 1 );
retv[index + 1] = NULL;
if ( strcasecmp( retv[index]->name, cmd ) == 0 ) {
if ( strcasecmp ( retv[index]->name, cmd ) == 0 )
{
curr = index;
}
index++;
}
fclose( fd );
fclose ( fd );
}
if(curr < 0) {
retv = reallocate( retv, ( index+2 )*sizeof( element* ) );
retv[index] = allocate(sizeof(element));
retv[index]->index = 1;
snprintf(retv[index]->name, 1024, "%s", cmd);
index++;
}else {
retv[curr]->index++;
if ( curr < 0 )
{
retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) );
retv[index] = allocate ( sizeof ( element ) );
retv[index]->index = 1;
snprintf ( retv[index]->name, 1024, "%s", cmd );
index++;
}
else
{
retv[curr]->index++;
}
// Sort the list.
qsort(retv, index, sizeof(element*), element_sort_func);
qsort ( retv, index, sizeof ( element* ), element_sort_func );
/**
* Write out the last 25 results again.
*/
fd = fopen ( path, "w" );
if ( fd ) {
for ( int i = 0; i < ( int )index && i < 20; i++ ) {
if(retv[i]->name && retv[i]->name[0] != '\0') {
fprintf(fd, "%ld %s\n",
retv[i]->index,
retv[i]->name
);
if ( fd )
{
for ( int i = 0; i < ( int ) index && i < 20; i++ )
{
if ( retv[i]->name && retv[i]->name[0] != '\0' )
{
fprintf ( fd, "%ld %s\n",
retv[i]->index,
retv[i]->name
);
}
}
fclose( fd );
fclose ( fd );
}
for ( int i=0; retv != NULL && retv[i] != NULL; i++ ) {
free( retv[i] );
for ( int i = 0; retv != NULL && retv[i] != NULL; i++ )
{
free ( retv[i] );
}
free( retv );
free ( retv );
free( path );
free ( path );
return pid;
}
// execute sub-process
static void delete_entry( const char *cmd )
static void delete_entry ( const char *cmd )
{
int curr = -1;
unsigned int index = 0;
element **retv = NULL;
int curr = -1;
unsigned int index = 0;
element **retv = NULL;
/**
* This happens in non-critical time (After launching app)
* It is allowed to be a bit slower.
*/
char *path = allocate( strlen( cache_dir ) + strlen( RUN_CACHE_FILE )+3 );
sprintf( path, "%s/%s", cache_dir, RUN_CACHE_FILE );
char *path = allocate ( strlen ( cache_dir ) + strlen ( RUN_CACHE_FILE ) + 3 );
sprintf ( path, "%s/%s", cache_dir, RUN_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
if ( fd != NULL ) {
if ( fd != NULL )
{
char buffer[1024];
while ( fgets( buffer,1024,fd ) != NULL ) {
if(strlen(buffer) == 0) continue;
retv = reallocate( retv, ( index+2 )*sizeof( element* ) );
retv[index] = allocate(sizeof(element));
buffer[strlen( buffer )-1] = '\0';
while ( fgets ( buffer, 1024, fd ) != NULL )
{
if ( strlen ( buffer ) == 0 )
{
continue;
}
retv = reallocate ( retv, ( index + 2 ) * sizeof ( element* ) );
retv[index] = allocate ( sizeof ( element ) );
buffer[strlen ( buffer ) - 1] = '\0';
char * start = NULL;
retv[index]->index = strtol(buffer, &start, 10);
snprintf(retv[index]->name, 1024, "%s", start+1);
retv[index+1] = NULL;
retv[index]->index = strtol ( buffer, &start, 10 );
snprintf ( retv[index]->name, 1024, "%s", start + 1 );
retv[index + 1] = NULL;
if ( strcasecmp( retv[index]->name, cmd ) == 0 ) {
if ( strcasecmp ( retv[index]->name, cmd ) == 0 )
{
curr = index;
}
index++;
}
fclose( fd );
fclose ( fd );
}
/**
@ -197,88 +222,107 @@ static void delete_entry( const char *cmd )
*/
fd = fopen ( path, "w" );
if ( fd ) {
for ( int i = 0; i < ( int )index && i < 20; i++ ) {
if ( i != curr ) {
if(retv[i]->name && retv[i]->name[0] != '\0') {
fprintf(fd, "%ld %s\n",
retv[i]->index,
retv[i]->name
);
if ( fd )
{
for ( int i = 0; i < ( int ) index && i < 20; i++ )
{
if ( i != curr )
{
if ( retv[i]->name && retv[i]->name[0] != '\0' )
{
fprintf ( fd, "%ld %s\n",
retv[i]->index,
retv[i]->name
);
}
}
}
fclose( fd );
fclose ( fd );
}
for ( int i=0; retv != NULL && retv[i] != NULL; i++ ) {
free( retv[i] );
for ( int i = 0; retv != NULL && retv[i] != NULL; i++ )
{
free ( retv[i] );
}
free( retv );
free( path );
free ( retv );
free ( path );
}
static int sort_func ( const void *a, const void *b )
{
const char *astr = *( const char * const * )a;
const char *bstr = *( const char * const * )b;
return strcasecmp( astr,bstr );
const char *astr = *( const char * const * ) a;
const char *bstr = *( const char * const * ) b;
return strcasecmp ( astr, bstr );
}
static char ** get_apps ( )
{
unsigned int num_favorites = 0;
unsigned int index = 0;
char *path;
char **retv = NULL;
unsigned int num_favorites = 0;
unsigned int index = 0;
char *path;
char **retv = NULL;
#ifdef TIMING
struct timespec start, stop;
clock_gettime( CLOCK_REALTIME, &start );
clock_gettime ( CLOCK_REALTIME, &start );
#endif
if ( getenv( "PATH" ) == NULL ) return NULL;
if ( getenv ( "PATH" ) == NULL )
{
return NULL;
}
path = allocate( strlen( cache_dir ) + strlen( RUN_CACHE_FILE )+3 );
sprintf( path, "%s/%s", cache_dir, RUN_CACHE_FILE );
path = allocate ( strlen ( cache_dir ) + strlen ( RUN_CACHE_FILE ) + 3 );
sprintf ( path, "%s/%s", cache_dir, RUN_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
if ( fd != NULL ) {
if ( fd != NULL )
{
char buffer[1024];
while ( fgets( buffer,1024,fd ) != NULL ) {
if(strlen(buffer) == 0) continue;
buffer[strlen( buffer )-1] = '\0';
while ( fgets ( buffer, 1024, fd ) != NULL )
{
if ( strlen ( buffer ) == 0 )
{
continue;
}
buffer[strlen ( buffer ) - 1] = '\0';
char *start = NULL;
// Don't use result.
strtol(buffer, &start, 10);
if(start == NULL) continue;
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
retv[index] = strdup( start+1 );
retv[index+1] = NULL;
strtol ( buffer, &start, 10 );
if ( start == NULL )
{
continue;
}
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
retv[index] = strdup ( start + 1 );
retv[index + 1] = NULL;
index++;
num_favorites++;
}
fclose( fd );
fclose ( fd );
}
free( path );
free ( path );
path = strdup( getenv( "PATH" ) );
path = strdup ( getenv ( "PATH" ) );
for ( const char *dirname = strtok( path, ":" ); dirname != NULL; dirname = strtok( NULL, ":" ) ) {
DIR *dir = opendir( dirname );
for ( const char *dirname = strtok ( path, ":" ); dirname != NULL; dirname = strtok ( NULL, ":" ) )
{
DIR *dir = opendir ( dirname );
if ( dir != NULL ) {
if ( dir != NULL )
{
struct dirent *dent;
while ( ( dent=readdir( dir ) )!=NULL ) {
while ( ( dent = readdir ( dir ) ) != NULL )
{
if ( dent->d_type != DT_REG &&
dent->d_type != DT_LNK &&
dent->d_type != DT_UNKNOWN ) {
dent->d_type != DT_UNKNOWN )
{
continue;
}
@ -286,72 +330,93 @@ static char ** get_apps ( )
// This is a nice little penalty, but doable? time will tell.
// given num_favorites is max 25.
for ( unsigned int j = 0; found == 0 && j < num_favorites; j++ ) {
if ( strcasecmp( dent->d_name, retv[j] ) == 0 ) found = 1;
for ( unsigned int j = 0; found == 0 && j < num_favorites; j++ )
{
if ( strcasecmp ( dent->d_name, retv[j] ) == 0 )
{
found = 1;
}
}
if ( found == 1 ) continue;
if ( found == 1 )
{
continue;
}
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
retv[index] = strdup( dent->d_name );
retv[index+1] = NULL;
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
retv[index] = strdup ( dent->d_name );
retv[index + 1] = NULL;
index++;
}
closedir( dir );
closedir ( dir );
}
}
// TODO: check this is still fast enough. (takes 1ms on laptop.)
if(index > num_favorites) {
qsort( &retv[num_favorites],index-num_favorites, sizeof( char* ), sort_func );
if ( index > num_favorites )
{
qsort ( &retv[num_favorites], index - num_favorites, sizeof ( char* ), sort_func );
}
free( path );
free ( path );
#ifdef TIMING
clock_gettime( CLOCK_REALTIME, &stop );
clock_gettime ( CLOCK_REALTIME, &stop );
if ( stop.tv_sec != start.tv_sec ) {
stop.tv_nsec += ( stop.tv_sec-start.tv_sec )*1e9;
if ( stop.tv_sec != start.tv_sec )
{
stop.tv_nsec += ( stop.tv_sec - start.tv_sec ) * 1e9;
}
long diff = stop.tv_nsec-start.tv_nsec;
printf( "Time elapsed: %ld us\n", diff/1000 );
long diff = stop.tv_nsec - start.tv_nsec;
printf ( "Time elapsed: %ld us\n", diff / 1000 );
#endif
return retv;
}
SwitcherMode run_switcher_dialog ( char **input )
{
int shift=0;
int selected_line = 0;
SwitcherMode retv = MODE_EXIT;
int shift = 0;
int selected_line = 0;
SwitcherMode retv = MODE_EXIT;
// act as a launcher
char **cmd_list = get_apps( );
char **cmd_list = get_apps ( );
if ( cmd_list == NULL ) {
cmd_list = allocate( 2*sizeof( char * ) );
cmd_list[0] = strdup( "No applications found" );
if ( cmd_list == NULL )
{
cmd_list = allocate ( 2 * sizeof ( char * ) );
cmd_list[0] = strdup ( "No applications found" );
cmd_list[1] = NULL;
}
int mretv = menu( cmd_list, input, "$", NULL, &shift,token_match, NULL, &selected_line );
int mretv = menu ( cmd_list, input, "$", NULL, &shift, token_match, NULL, &selected_line );
if ( mretv == MENU_NEXT ) {
if ( mretv == MENU_NEXT )
{
retv = NEXT_DIALOG;
} else if ( mretv == MENU_OK && cmd_list[selected_line] != NULL ) {
exec_cmd( cmd_list[selected_line], shift );
} else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) {
exec_cmd( *input, shift );
} else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] ) {
}
else if ( mretv == MENU_OK && cmd_list[selected_line] != NULL )
{
exec_cmd ( cmd_list[selected_line], shift );
}
else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' )
{
exec_cmd ( *input, shift );
}
else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] )
{
delete_entry ( cmd_list[selected_line] );
retv = RUN_DIALOG;
}
for ( int i=0; cmd_list != NULL && cmd_list[i] != NULL; i++ ) {
free( cmd_list[i] );
for ( int i = 0; cmd_list != NULL && cmd_list[i] != NULL; i++ )
{
free ( cmd_list[i] );
}
if ( cmd_list != NULL ) free( cmd_list );
if ( cmd_list != NULL )
{
free ( cmd_list );
}
return retv;
}

View File

@ -45,54 +45,61 @@
#include <time.h>
#endif
#define SSH_CACHE_FILE "rofi.sshcache"
#define SSH_CACHE_FILE "rofi.sshcache"
static inline int execshssh( const char *host )
static inline int execshssh ( const char *host )
{
return execlp( config.terminal_emulator, config.terminal_emulator, "-e", "ssh", host, NULL );
return execlp ( config.terminal_emulator, config.terminal_emulator, "-e", "ssh", host, NULL );
}
// execute sub-process
static pid_t exec_ssh( const char *cmd )
static pid_t exec_ssh ( const char *cmd )
{
if ( !cmd || !cmd[0] ) return -1;
signal( SIGCHLD, catch_exit );
pid_t pid = fork();
if ( !pid ) {
setsid();
execshssh( cmd );
exit( EXIT_FAILURE );
if ( !cmd || !cmd[0] )
{
return -1;
}
int curr = -1;
unsigned int index = 0;
char **retv = NULL;
signal ( SIGCHLD, catch_exit );
pid_t pid = fork ();
if ( !pid )
{
setsid ();
execshssh ( cmd );
exit ( EXIT_FAILURE );
}
int curr = -1;
unsigned int index = 0;
char **retv = NULL;
/**
* This happens in non-critical time (After launching app)
* It is allowed to be a bit slower.
*/
char *path = allocate( strlen( cache_dir ) + strlen( SSH_CACHE_FILE )+3 );
sprintf( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
char *path = allocate ( strlen ( cache_dir ) + strlen ( SSH_CACHE_FILE ) + 3 );
sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
if ( fd != NULL ) {
if ( fd != NULL )
{
char buffer[1024];
while ( fgets( buffer,1024,fd ) != NULL ) {
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
buffer[strlen( buffer )-1] = '\0';
retv[index] = strdup( buffer );
retv[index+1] = NULL;
while ( fgets ( buffer, 1024, fd ) != NULL )
{
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
buffer[strlen ( buffer ) - 1] = '\0';
retv[index] = strdup ( buffer );
retv[index + 1] = NULL;
if ( strcasecmp( retv[index], cmd ) == 0 ) {
if ( strcasecmp ( retv[index], cmd ) == 0 )
{
curr = index;
}
index++;
}
fclose( fd );
fclose ( fd );
}
/**
@ -100,63 +107,73 @@ static pid_t exec_ssh( const char *cmd )
*/
fd = fopen ( path, "w" );
if ( fd ) {
if ( fd )
{
// Last one goes on top!
fputs( cmd, fd );
fputc( '\n', fd );
fputs ( cmd, fd );
fputc ( '\n', fd );
for ( int i = 0; i < ( int )index && i < 20; i++ ) {
if ( i != curr ) {
fputs( retv[i], fd );
fputc( '\n', fd );
for ( int i = 0; i < ( int ) index && i < 20; i++ )
{
if ( i != curr )
{
fputs ( retv[i], fd );
fputc ( '\n', fd );
}
}
fclose( fd );
fclose ( fd );
}
for ( int i=0; retv != NULL && retv[i] != NULL; i++ ) {
free( retv[i] );
for ( int i = 0; retv != NULL && retv[i] != NULL; i++ )
{
free ( retv[i] );
}
free( retv );
free ( retv );
free( path );
free ( path );
return pid;
}
static void delete_ssh( const char *cmd )
static void delete_ssh ( const char *cmd )
{
if ( !cmd || !cmd[0] ) return ;
if ( !cmd || !cmd[0] )
{
return;
}
int curr = -1;
unsigned int index = 0;
char **retv = NULL;
int curr = -1;
unsigned int index = 0;
char **retv = NULL;
/**
* This happens in non-critical time (After launching app)
* It is allowed to be a bit slower.
*/
char *path = allocate( strlen( cache_dir ) + strlen( SSH_CACHE_FILE )+3 );
sprintf( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
char *path = allocate ( strlen ( cache_dir ) + strlen ( SSH_CACHE_FILE ) + 3 );
sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
if ( fd != NULL ) {
if ( fd != NULL )
{
char buffer[1024];
while ( fgets( buffer,1024,fd ) != NULL ) {
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
buffer[strlen( buffer )-1] = '\0';
retv[index] = strdup( buffer );
retv[index+1] = NULL;
while ( fgets ( buffer, 1024, fd ) != NULL )
{
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
buffer[strlen ( buffer ) - 1] = '\0';
retv[index] = strdup ( buffer );
retv[index + 1] = NULL;
if ( strcasecmp( retv[index], cmd ) == 0 ) {
if ( strcasecmp ( retv[index], cmd ) == 0 )
{
curr = index;
}
index++;
}
fclose( fd );
fclose ( fd );
}
/**
@ -164,118 +181,146 @@ static void delete_ssh( const char *cmd )
*/
fd = fopen ( path, "w" );
if ( fd ) {
for ( int i = 0; i < ( int )index && i < 20; i++ ) {
if ( i != curr ) {
fputs( retv[i], fd );
fputc( '\n', fd );
if ( fd )
{
for ( int i = 0; i < ( int ) index && i < 20; i++ )
{
if ( i != curr )
{
fputs ( retv[i], fd );
fputc ( '\n', fd );
}
}
fclose( fd );
fclose ( fd );
}
for ( int i=0; retv != NULL && retv[i] != NULL; i++ ) {
free( retv[i] );
for ( int i = 0; retv != NULL && retv[i] != NULL; i++ )
{
free ( retv[i] );
}
free( retv );
free( path );
free ( retv );
free ( path );
}
static int sort_func ( const void *a, const void *b )
{
const char *astr = *( const char * const * )a;
const char *bstr = *( const char * const * )b;
return strcasecmp( astr,bstr );
const char *astr = *( const char * const * ) a;
const char *bstr = *( const char * const * ) b;
return strcasecmp ( astr, bstr );
}
static char ** get_ssh ( )
{
unsigned int num_favorites = 0;
unsigned int index = 0;
char *path;
char **retv = NULL;
unsigned int num_favorites = 0;
unsigned int index = 0;
char *path;
char **retv = NULL;
#ifdef TIMING
struct timespec start, stop;
clock_gettime( CLOCK_REALTIME, &start );
clock_gettime ( CLOCK_REALTIME, &start );
#endif
if ( getenv( "HOME" ) == NULL ) return NULL;
if ( getenv ( "HOME" ) == NULL )
{
return NULL;
}
path = allocate( strlen( cache_dir ) + strlen( "/"SSH_CACHE_FILE )+2 );
sprintf( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
path = allocate ( strlen ( cache_dir ) + strlen ( "/"SSH_CACHE_FILE ) + 2 );
sprintf ( path, "%s/%s", cache_dir, SSH_CACHE_FILE );
FILE *fd = fopen ( path, "r" );
char buffer[1024];
if ( fd != NULL ) {
while ( fgets( buffer,1024,fd ) != NULL ) {
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
buffer[strlen( buffer )-1] = '\0';
retv[index] = strdup( buffer );
retv[index+1] = NULL;
if ( fd != NULL )
{
while ( fgets ( buffer, 1024, fd ) != NULL )
{
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
buffer[strlen ( buffer ) - 1] = '\0';
retv[index] = strdup ( buffer );
retv[index + 1] = NULL;
index++;
num_favorites++;
}
fclose( fd );
fclose ( fd );
}
free( path );
const char *hd = getenv( "HOME" );
path = allocate( strlen( hd ) + strlen( ".ssh/config" )+3 );
sprintf( path, "%s/%s", hd, ".ssh/config" );
free ( path );
const char *hd = getenv ( "HOME" );
path = allocate ( strlen ( hd ) + strlen ( ".ssh/config" ) + 3 );
sprintf ( path, "%s/%s", hd, ".ssh/config" );
fd = fopen ( path, "r" );
if ( fd != NULL ) {
while ( fgets( buffer,1024,fd ) != NULL ) {
if ( strncasecmp( buffer, "Host", 4 ) == 0 ) {
int start = 0, stop=0;
buffer[strlen( buffer )-1] = '\0';
if ( fd != NULL )
{
while ( fgets ( buffer, 1024, fd ) != NULL )
{
if ( strncasecmp ( buffer, "Host", 4 ) == 0 )
{
int start = 0, stop = 0;
buffer[strlen ( buffer ) - 1] = '\0';
for ( start=4; isspace( buffer[start] ); start++ );
for ( start = 4; isspace ( buffer[start] ); start++ )
{
;
}
for ( stop=start; isalnum( buffer[stop] ) ||
for ( stop = start; isalnum ( buffer[stop] ) ||
buffer[stop] == '_' ||
buffer[stop] == '.' ; stop++ );
buffer[stop] == '.'; stop++ )
{
;
}
int found = 0;
if ( start == stop ) continue;
if ( start == stop )
{
continue;
}
// This is a nice little penalty, but doable? time will tell.
// given num_favorites is max 25.
for ( unsigned int j = 0; found == 0 && j < num_favorites; j++ ) {
if ( strncasecmp( &buffer[start], retv[j],stop-start ) == 0 ) found = 1;
for ( unsigned int j = 0; found == 0 && j < num_favorites; j++ )
{
if ( strncasecmp ( &buffer[start], retv[j], stop - start ) == 0 )
{
found = 1;
}
}
if ( found == 1 ) continue;
if ( found == 1 )
{
continue;
}
retv = reallocate( retv, ( index+2 )*sizeof( char* ) );
retv[index] = strndup( &buffer[start], stop-start );
retv[index+1] = NULL;
retv = reallocate ( retv, ( index + 2 ) * sizeof ( char* ) );
retv[index] = strndup ( &buffer[start], stop - start );
retv[index + 1] = NULL;
index++;
}
}
fclose( fd );
fclose ( fd );
}
// TODO: check this is still fast enough. (takes 1ms on laptop.)
if(index > num_favorites) {
qsort( &retv[num_favorites],index-num_favorites, sizeof( char* ), sort_func );
if ( index > num_favorites )
{
qsort ( &retv[num_favorites], index - num_favorites, sizeof ( char* ), sort_func );
}
free( path );
free ( path );
#ifdef TIMING
clock_gettime( CLOCK_REALTIME, &stop );
clock_gettime ( CLOCK_REALTIME, &stop );
if ( stop.tv_sec != start.tv_sec ) {
stop.tv_nsec += ( stop.tv_sec-start.tv_sec )*1e9;
if ( stop.tv_sec != start.tv_sec )
{
stop.tv_nsec += ( stop.tv_sec - start.tv_sec ) * 1e9;
}
long diff = stop.tv_nsec-start.tv_nsec;
printf( "Time elapsed: %ld us\n", diff/1000 );
long diff = stop.tv_nsec - start.tv_nsec;
printf ( "Time elapsed: %ld us\n", diff / 1000 );
#endif
return retv;
}
@ -284,35 +329,47 @@ SwitcherMode ssh_switcher_dialog ( char **input )
{
SwitcherMode retv = MODE_EXIT;
// act as a launcher
char **cmd_list = get_ssh( );
char **cmd_list = get_ssh ( );
if ( cmd_list == NULL ) {
cmd_list = allocate( 2*sizeof( char * ) );
cmd_list[0] = strdup( "No ssh hosts found" );
if ( cmd_list == NULL )
{
cmd_list = allocate ( 2 * sizeof ( char * ) );
cmd_list[0] = strdup ( "No ssh hosts found" );
cmd_list[1] = NULL;
}
int shift=0;
int shift = 0;
int selected_line = 0;
int mretv = menu( cmd_list, input, "ssh", NULL, &shift,token_match, NULL , &selected_line );
int mretv = menu ( cmd_list, input, "ssh", NULL, &shift, token_match, NULL, &selected_line );
if ( mretv == MENU_NEXT ) {
if ( mretv == MENU_NEXT )
{
retv = NEXT_DIALOG;
} else if ( mretv == MENU_OK && cmd_list[selected_line] != NULL ) {
exec_ssh( cmd_list[selected_line] );
} else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' ) {
exec_ssh( *input );
} else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] ) {
}
else if ( mretv == MENU_OK && cmd_list[selected_line] != NULL )
{
exec_ssh ( cmd_list[selected_line] );
}
else if ( mretv == MENU_CUSTOM_INPUT && *input != NULL && *input[0] != '\0' )
{
exec_ssh ( *input );
}
else if ( mretv == MENU_ENTRY_DELETE && cmd_list[selected_line] )
{
delete_ssh ( cmd_list[selected_line] );
// Stay
retv = SSH_DIALOG;
}
for ( int i=0; cmd_list[i] != NULL; i++ ) {
free( cmd_list[i] );
for ( int i = 0; cmd_list[i] != NULL; i++ )
{
free ( cmd_list[i] );
}
if ( cmd_list != NULL ) free( cmd_list );
if ( cmd_list != NULL )
{
free ( cmd_list );
}
return retv;
}

View File

@ -1,29 +1,29 @@
/*
MIT/X11 License
Copyright (c) 2012 Sean Pringle <sean.pringle@gmail.com>
Modified (c) 2013-2014 Qball Cow <qball@gmpclient.org>
MIT/X11 License
Copyright (c) 2012 Sean Pringle <sean.pringle@gmail.com>
Modified (c) 2013-2014 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:
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 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.
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.
*/
*/
#define _GNU_SOURCE
#include <X11/X.h>
@ -39,297 +39,342 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "rofi.h"
#include "textbox.h"
#define SIDE_MARGIN 3
#define SIDE_MARGIN 3
extern Display *display;
void textbox_moveresize( textbox *tb, int x, int y, int w, int h );
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h );
// Xft text box, optionally editable
textbox* textbox_create( Window parent,
TextboxFlags flags,
short x, short y, short w, short h,
char *font, char *fg, char *bg,
char *text, char *prompt )
textbox* textbox_create ( Window parent,
TextboxFlags flags,
short x, short y, short w, short h,
char *font, char *fg, char *bg,
char *text, char *prompt )
{
textbox *tb = calloc( 1, sizeof( textbox ) );
textbox *tb = calloc ( 1, sizeof ( textbox ) );
tb->flags = flags;
tb->flags = flags;
tb->parent = parent;
tb->x = x;
tb->y = y;
tb->w = MAX( 1, w );
tb->h = MAX( 1, h );
tb->w = MAX ( 1, w );
tb->h = MAX ( 1, h );
XColor color;
Colormap map = DefaultColormap( display, DefaultScreen( display ) );
unsigned int cp = XAllocNamedColor( display, map, bg, &color, &color ) ? color.pixel: None;
XColor color;
Colormap map = DefaultColormap ( display, DefaultScreen ( display ) );
unsigned int cp = XAllocNamedColor ( display, map, bg, &color, &color ) ? color.pixel : None;
tb->window = XCreateSimpleWindow( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, None, cp );
tb->window = XCreateSimpleWindow ( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, None, cp );
// need to preload the font to calc line height
textbox_font( tb, font, fg, bg );
textbox_font ( tb, font, fg, bg );
tb->prompt = strdup( prompt ? prompt: "" );
textbox_text( tb, text ? text: "" );
textbox_cursor_end( tb );
tb->prompt = strdup ( prompt ? prompt : "" );
textbox_text ( tb, text ? text : "" );
textbox_cursor_end ( tb );
// auto height/width modes get handled here
textbox_moveresize( tb, tb->x, tb->y, tb->w, tb->h );
textbox_moveresize ( tb, tb->x, tb->y, tb->w, tb->h );
// edit mode controls
if ( tb->flags & TB_EDITABLE ) {
tb->xim = XOpenIM( display, NULL, NULL, NULL );
tb->xic = XCreateIC( tb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, tb->window, XNFocusWindow, tb->window, NULL );
if ( tb->flags & TB_EDITABLE )
{
tb->xim = XOpenIM ( display, NULL, NULL, NULL );
tb->xic = XCreateIC ( tb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, tb->window, XNFocusWindow, tb->window, NULL );
}
return tb;
}
// set an Xft font by name
void textbox_font( textbox *tb, char *font, char *fg, char *bg )
void textbox_font ( textbox *tb, char *font, char *fg, char *bg )
{
if ( tb->font ) {
if ( tb->font )
{
XftColorFree ( display,
DefaultVisual( display, DefaultScreen( display ) ),
DefaultColormap( display, DefaultScreen( display ) ),
DefaultVisual ( display, DefaultScreen ( display ) ),
DefaultColormap ( display, DefaultScreen ( display ) ),
&tb->color_fg );
XftColorFree ( display,
DefaultVisual( display, DefaultScreen( display ) ),
DefaultColormap( display, DefaultScreen( display ) ),
DefaultVisual ( display, DefaultScreen ( display ) ),
DefaultColormap ( display, DefaultScreen ( display ) ),
&tb->color_bg );
XftFontClose( display, tb->font );
XftFontClose ( display, tb->font );
}
tb->font = XftFontOpenName( display, DefaultScreen( display ), font );
tb->font = XftFontOpenName ( display, DefaultScreen ( display ), font );
XftColorAllocName( display, DefaultVisual( display, DefaultScreen( display ) ), DefaultColormap( display, DefaultScreen( display ) ), fg, &tb->color_fg );
XftColorAllocName( display, DefaultVisual( display, DefaultScreen( display ) ), DefaultColormap( display, DefaultScreen( display ) ), bg, &tb->color_bg );
XftColorAllocName ( display, DefaultVisual ( display, DefaultScreen ( display ) ), DefaultColormap ( display, DefaultScreen ( display ) ), fg, &tb->color_fg );
XftColorAllocName ( display, DefaultVisual ( display, DefaultScreen ( display ) ), DefaultColormap ( display, DefaultScreen ( display ) ), bg, &tb->color_bg );
}
// outer code may need line height, width, etc
void textbox_extents( textbox *tb )
void textbox_extents ( textbox *tb )
{
int length = strlen( tb->text ) + strlen( tb->prompt ) +1;
int length = strlen ( tb->text ) + strlen ( tb->prompt ) + 1;
char line[length + 1 ];
sprintf( line, "%s %s", tb->prompt, tb->text );
XftTextExtentsUtf8( display, tb->font, ( unsigned char* )line, length, &tb->extents );
sprintf ( line, "%s %s", tb->prompt, tb->text );
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) line, length, &tb->extents );
}
// set the default text to display
void textbox_text( textbox *tb, char *text )
void textbox_text ( textbox *tb, char *text )
{
if ( tb->text ) free( tb->text );
if ( tb->text )
{
free ( tb->text );
}
tb->text = strdup( text );
tb->cursor = MAX( 0,MIN( ( int )strlen( text ), tb->cursor ) );
textbox_extents( tb );
tb->text = strdup ( text );
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) );
textbox_extents ( tb );
}
// within the parent. handled auto width/height modes
void textbox_moveresize( textbox *tb, int x, int y, int w, int h )
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
{
if ( tb->flags & TB_AUTOHEIGHT )
{
h = tb->font->ascent + tb->font->descent;
}
if ( tb->flags & TB_AUTOWIDTH )
{
w = tb->extents.width;
}
if ( x != tb->x || y != tb->y || w != tb->w || h != tb->h ) {
if ( x != tb->x || y != tb->y || w != tb->w || h != tb->h )
{
tb->x = x;
tb->y = y;
tb->w = MAX( 1, w );
tb->h = MAX( 1, h );
XMoveResizeWindow( display, tb->window, tb->x, tb->y, tb->w, tb->h );
tb->w = MAX ( 1, w );
tb->h = MAX ( 1, h );
XMoveResizeWindow ( display, tb->window, tb->x, tb->y, tb->w, tb->h );
}
}
void textbox_show( textbox *tb )
void textbox_show ( textbox *tb )
{
XMapWindow( display, tb->window );
XMapWindow ( display, tb->window );
}
// will also unmap the window if still displayed
void textbox_free( textbox *tb )
void textbox_free ( textbox *tb )
{
if ( tb->flags & TB_EDITABLE ) {
XDestroyIC( tb->xic );
XCloseIM( tb->xim );
if ( tb->flags & TB_EDITABLE )
{
XDestroyIC ( tb->xic );
XCloseIM ( tb->xim );
}
if ( tb->text ) free( tb->text );
if ( tb->text )
{
free ( tb->text );
}
if ( tb->prompt ) free( tb->prompt );
if ( tb->prompt )
{
free ( tb->prompt );
}
if ( tb->font ) {
if ( tb->font )
{
XftColorFree ( display,
DefaultVisual( display, DefaultScreen( display ) ),
DefaultColormap( display, DefaultScreen( display ) ),
DefaultVisual ( display, DefaultScreen ( display ) ),
DefaultColormap ( display, DefaultScreen ( display ) ),
&tb->color_fg );
XftColorFree ( display,
DefaultVisual( display, DefaultScreen( display ) ),
DefaultColormap( display, DefaultScreen( display ) ),
DefaultVisual ( display, DefaultScreen ( display ) ),
DefaultColormap ( display, DefaultScreen ( display ) ),
&tb->color_bg );
XftFontClose( display, tb->font );
XftFontClose ( display, tb->font );
}
XDestroyWindow( display, tb->window );
free( tb );
XDestroyWindow ( display, tb->window );
free ( tb );
}
void textbox_draw( textbox *tb )
void textbox_draw ( textbox *tb )
{
XGlyphInfo extents;
GC context = XCreateGC( display, tb->window, 0, 0 );
Pixmap canvas = XCreatePixmap( display, tb->window, tb->w, tb->h, DefaultDepth( display, DefaultScreen( display ) ) );
XftDraw *draw = XftDrawCreate( display, canvas, DefaultVisual( display, DefaultScreen( display ) ), DefaultColormap( display, DefaultScreen( display ) ) );
GC context = XCreateGC ( display, tb->window, 0, 0 );
Pixmap canvas = XCreatePixmap ( display, tb->window, tb->w, tb->h, DefaultDepth ( display, DefaultScreen ( display ) ) );
XftDraw *draw = XftDrawCreate ( display, canvas, DefaultVisual ( display, DefaultScreen ( display ) ), DefaultColormap ( display, DefaultScreen ( display ) ) );
// clear canvas
XftDrawRect( draw, &tb->color_bg, 0, 0, tb->w, tb->h );
XftDrawRect ( draw, &tb->color_bg, 0, 0, tb->w, tb->h );
char *line = tb->text,
*text = tb->text ? tb->text: "",
*prompt = tb->prompt ? tb->prompt: "";
char *line = tb->text,
*text = tb->text ? tb->text : "",
*prompt = tb->prompt ? tb->prompt : "";
int text_len = strlen( text );
int text_len = strlen ( text );
int length = text_len;
int line_height = tb->font->ascent + tb->font->descent;
int line_width = 0;
int cursor_x = 0;
int cursor_width = MAX( 2, line_height/10 );
int cursor_x = 0;
int cursor_width = MAX ( 2, line_height / 10 );
if ( tb->flags & TB_EDITABLE ) {
if ( tb->flags & TB_EDITABLE )
{
int cursor_offset = 0;
int prompt_len = strlen( prompt ) +1;
length = text_len + prompt_len;
cursor_offset = MIN( tb->cursor + prompt_len, length );
int prompt_len = strlen ( prompt ) + 1;
length = text_len + prompt_len;
cursor_offset = MIN ( tb->cursor + prompt_len, length );
line = alloca( length + 10 );
sprintf( line, "%s %s", prompt, text );
line = alloca ( length + 10 );
sprintf ( line, "%s %s", prompt, text );
// replace spaces so XftTextExtents8 includes their width
for ( int i = 0; i < length; i++ ) if ( isspace( line[i] ) ) line[i] = '_';
for ( int i = 0; i < length; i++ )
{
if ( isspace ( line[i] ) )
{
line[i] = '_';
}
}
// calc cursor position
XftTextExtentsUtf8( display, tb->font, ( unsigned char* )line, cursor_offset, &extents );
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) line, cursor_offset, &extents );
cursor_x = extents.width;
// restore correct text string with spaces
sprintf( line, "%s %s", prompt, text );
sprintf ( line, "%s %s", prompt, text );
}
// calc full input text width
// Calculate the right size, so no characters are cut off.
// TODO: Check performance of this.
while ( 1 ) {
XftTextExtentsUtf8( display, tb->font, ( unsigned char* )line, length, &extents );
while ( 1 )
{
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) line, length, &extents );
line_width = extents.width;
if ( line_width < ( tb->w-2*SIDE_MARGIN ) ) break;
if ( line_width < ( tb->w - 2 * SIDE_MARGIN ) )
{
break;
}
for(length-=1; length > 0 && (line[length]&0xc0) == 0x80; length -=1);
for ( length -= 1; length > 0 && ( line[length] & 0xc0 ) == 0x80; length -= 1 )
{
;
}
}
int x = SIDE_MARGIN, y = tb->font->ascent;
if ( tb->flags & TB_RIGHT ) x = tb->w - line_width;
if ( tb->flags & TB_RIGHT )
{
x = tb->w - line_width;
}
if ( tb->flags & TB_CENTER ) x = ( tb->w - line_width ) / 2;
if ( tb->flags & TB_CENTER )
{
x = ( tb->w - line_width ) / 2;
}
// draw the text, including any prompt in edit mode
XftDrawStringUtf8( draw, &tb->color_fg, tb->font, x, y, ( unsigned char* )line, length );
XftDrawStringUtf8 ( draw, &tb->color_fg, tb->font, x, y, ( unsigned char * ) line, length );
// draw the cursor
if ( tb->flags & TB_EDITABLE )
XftDrawRect( draw, &tb->color_fg, cursor_x+SIDE_MARGIN, 2, cursor_width, line_height-4 );
{
XftDrawRect ( draw, &tb->color_fg, cursor_x + SIDE_MARGIN, 2, cursor_width, line_height - 4 );
}
XftDrawRect( draw, &tb->color_bg, tb->w-SIDE_MARGIN, 0, SIDE_MARGIN, tb->h );
XftDrawRect ( draw, &tb->color_bg, tb->w - SIDE_MARGIN, 0, SIDE_MARGIN, tb->h );
// flip canvas to window
XCopyArea( display, canvas, tb->window, context, 0, 0, tb->w, tb->h, 0, 0 );
XCopyArea ( display, canvas, tb->window, context, 0, 0, tb->w, tb->h, 0, 0 );
XFreeGC( display, context );
XftDrawDestroy( draw );
XFreePixmap( display, canvas );
XFreeGC ( display, context );
XftDrawDestroy ( draw );
XFreePixmap ( display, canvas );
}
static size_t nextrune(textbox *tb, int inc) {
static size_t nextrune ( textbox *tb, int inc )
{
ssize_t n;
/* return location of next utf8 rune in the given direction (+1 or -1) */
for(n = tb->cursor + inc; n + inc >= 0 && (tb->text[n] & 0xc0) == 0x80; n += inc);
for ( n = tb->cursor + inc; n + inc >= 0 && ( tb->text[n] & 0xc0 ) == 0x80; n += inc )
{
;
}
return n;
}
// cursor handling for edit mode
void textbox_cursor( textbox *tb, int pos )
void textbox_cursor ( textbox *tb, int pos )
{
tb->cursor = MAX( 0, MIN( ( int )strlen( tb->text ), pos ) );
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( tb->text ), pos ) );
}
// move right
void textbox_cursor_inc( textbox *tb )
void textbox_cursor_inc ( textbox *tb )
{
textbox_cursor( tb, nextrune(tb, 1) );
textbox_cursor ( tb, nextrune ( tb, 1 ) );
}
// move left
void textbox_cursor_dec( textbox *tb )
void textbox_cursor_dec ( textbox *tb )
{
textbox_cursor( tb, nextrune(tb,-1) );
textbox_cursor ( tb, nextrune ( tb, -1 ) );
}
// end of line
void textbox_cursor_end( textbox *tb )
void textbox_cursor_end ( textbox *tb )
{
tb->cursor = ( int )strlen( tb->text );
tb->cursor = ( int ) strlen ( tb->text );
}
// insert text
void textbox_insert( textbox *tb, int pos, char *str )
void textbox_insert ( textbox *tb, int pos, char *str )
{
int len = ( int )strlen( tb->text ), slen = ( int )strlen( str );
pos = MAX( 0, MIN( len, pos ) );
int len = ( int ) strlen ( tb->text ), slen = ( int ) strlen ( str );
pos = MAX ( 0, MIN ( len, pos ) );
// expand buffer
tb->text = realloc( tb->text, len + slen + 1 );
tb->text = realloc ( tb->text, len + slen + 1 );
// move everything after cursor upward
char *at = tb->text + pos;
memmove( at + slen, at, len - pos + 1 );
memmove ( at + slen, at, len - pos + 1 );
// insert new str
memmove( at, str, slen );
textbox_extents( tb );
memmove ( at, str, slen );
textbox_extents ( tb );
}
// remove text
void textbox_delete( textbox *tb, int pos, int dlen )
void textbox_delete ( textbox *tb, int pos, int dlen )
{
int len = strlen( tb->text );
pos = MAX( 0, MIN( len, pos ) );
int len = strlen ( tb->text );
pos = MAX ( 0, MIN ( len, pos ) );
// move everything after pos+dlen down
char *at = tb->text + pos;
memmove( at, at + dlen, len - pos );
textbox_extents( tb );
memmove ( at, at + dlen, len - pos );
textbox_extents ( tb );
}
// delete on character
void textbox_cursor_del( textbox *tb )
void textbox_cursor_del ( textbox *tb )
{
int del_r = nextrune(tb, 1);
textbox_delete( tb, tb->cursor, del_r-tb->cursor );
int del_r = nextrune ( tb, 1 );
textbox_delete ( tb, tb->cursor, del_r - tb->cursor );
}
// back up and delete one character
void textbox_cursor_bkspc( textbox *tb )
void textbox_cursor_bkspc ( textbox *tb )
{
if ( tb->cursor > 0 ) {
textbox_cursor_dec( tb );
textbox_cursor_del( tb );
if ( tb->cursor > 0 )
{
textbox_cursor_dec ( tb );
textbox_cursor_del ( tb );
}
}
@ -337,42 +382,56 @@ void textbox_cursor_bkspc( textbox *tb )
// 0 = unhandled
// 1 = handled
// -1 = handled and return pressed (finished)
int textbox_keypress( textbox *tb, XEvent *ev )
int textbox_keypress ( textbox *tb, XEvent *ev )
{
KeySym key;
Status stat;
char pad[32];
int len;
char pad[32];
int len;
if ( !( tb->flags & TB_EDITABLE ) ) return 0;
if ( !( tb->flags & TB_EDITABLE ) )
{
return 0;
}
len = Xutf8LookupString( tb->xic, &ev->xkey, pad, sizeof( pad ), &key, &stat );
len = Xutf8LookupString ( tb->xic, &ev->xkey, pad, sizeof ( pad ), &key, &stat );
pad[len] = 0;
if ( key == XK_Left ) {
textbox_cursor_dec( tb );
if ( key == XK_Left )
{
textbox_cursor_dec ( tb );
return 1;
} else if ( key == XK_Right ) {
textbox_cursor_inc( tb );
}
else if ( key == XK_Right )
{
textbox_cursor_inc ( tb );
return 1;
} /*else if ( key == XK_Home ) {
textbox_cursor_home( tb );
textbox_cursor_home( tb );
return 1;
} else if ( key == XK_End ) {
textbox_cursor_end( tb );
return 1;
} */
else if ( key == XK_Delete )
{
textbox_cursor_del ( tb );
return 1;
} else if ( key == XK_End ) {
textbox_cursor_end( tb );
}
else if ( key == XK_BackSpace )
{
textbox_cursor_bkspc ( tb );
return 1;
} */else if ( key == XK_Delete ) {
textbox_cursor_del( tb );
return 1;
} else if ( key == XK_BackSpace ) {
textbox_cursor_bkspc( tb );
return 1;
} else if ( key == XK_Return ) {
}
else if ( key == XK_Return )
{
return -1;
} else if ( !iscntrl( *pad ) ) {
textbox_insert( tb, tb->cursor, pad );
textbox_cursor_inc( tb );
}
else if ( !iscntrl ( *pad ) )
{
textbox_insert ( tb, tb->cursor, pad );
textbox_cursor_inc ( tb );
return 1;
}

View File

@ -34,64 +34,72 @@
// Big thanks to Sean Pringle for this code.
// This maps xresource options to config structure.
typedef enum {
typedef enum
{
xrm_String = 0,
xrm_Number = 1
} XrmOptionType;
typedef struct {
int type;
char * name ;
union {
typedef struct
{
int type;
char * name;
union
{
unsigned int * num;
char ** str;
char ** str;
};
} XrmOption;
XrmOption xrmOptions[] = {
{ xrm_Number, "opacity", { .num = &config.window_opacity } },
{ xrm_Number, "width", { .num = &config.menu_width } },
{ xrm_Number, "lines", { .num = &config.menu_lines } },
{ xrm_String, "font", { .str = &config.menu_font } },
{ xrm_String, "foreground", { .str = &config.menu_fg } },
{ xrm_String, "background", { .str = &config.menu_bg } },
{ xrm_String, "highlightfg", { .str = &config.menu_hlfg } },
{ xrm_String, "highlightbg", { .str = &config.menu_hlbg } },
{ xrm_String, "bordercolor", { .str = &config.menu_bc } },
{ xrm_Number, "padding", { .num = &config.padding } },
{ xrm_Number, "borderwidth", { .num = &config.menu_bw} },
{ xrm_Number, "opacity", { .num = &config.window_opacity } },
{ xrm_Number, "width", { .num = &config.menu_width } },
{ xrm_Number, "lines", { .num = &config.menu_lines } },
{ xrm_String, "font", { .str = &config.menu_font } },
{ xrm_String, "foreground", { .str = &config.menu_fg } },
{ xrm_String, "background", { .str = &config.menu_bg } },
{ xrm_String, "highlightfg", { .str = &config.menu_hlfg } },
{ xrm_String, "highlightbg", { .str = &config.menu_hlbg } },
{ xrm_String, "bordercolor", { .str = &config.menu_bc } },
{ xrm_Number, "padding", { .num = &config.padding } },
{ xrm_Number, "borderwidth", { .num = &config.menu_bw } },
{ xrm_String, "terminal", { .str = &config.terminal_emulator } },
};
void parse_xresource_options( Display *display )
void parse_xresource_options ( Display *display )
{
// Map Xresource entries to simpleswitcher config options.
XrmInitialize();
XrmInitialize ();
char * xRMS = XResourceManagerString ( display );
if ( xRMS != NULL ) {
if ( xRMS != NULL )
{
XrmDatabase xDB = XrmGetStringDatabase ( xRMS );
char * xrmType;
XrmValue xrmValue;
char * xrmType;
XrmValue xrmValue;
// TODO: update when we have new name.
const char * namePrefix = "rofi";
const char * classPrefix = "Simpleswitcher";
const char * namePrefix = "rofi";
const char * classPrefix = "Simpleswitcher";
for ( unsigned int i = 0; i < sizeof ( xrmOptions ) / sizeof ( *xrmOptions ); ++i ) {
char *name = ( char* ) allocate( ( strlen ( namePrefix ) + 1 + strlen ( xrmOptions[i].name ) ) *
sizeof ( char ) + 1 );
char *class = ( char* ) allocate( ( strlen ( classPrefix ) + 1 + strlen ( xrmOptions[i].name ) ) *
sizeof ( char ) + 1 );
for ( unsigned int i = 0; i < sizeof ( xrmOptions ) / sizeof ( *xrmOptions ); ++i )
{
char *name = ( char * ) allocate ( ( strlen ( namePrefix ) + 1 + strlen ( xrmOptions[i].name ) ) *
sizeof ( char ) + 1 );
char *class = ( char * ) allocate ( ( strlen ( classPrefix ) + 1 + strlen ( xrmOptions[i].name ) ) *
sizeof ( char ) + 1 );
sprintf ( name, "%s.%s", namePrefix, xrmOptions[i].name );
sprintf ( class, "%s.%s", classPrefix, xrmOptions[i].name );
if ( XrmGetResource ( xDB, name, class, &xrmType, &xrmValue ) ) {
if ( xrmOptions[i].type == xrm_String ) {
if ( XrmGetResource ( xDB, name, class, &xrmType, &xrmValue ) )
{
if ( xrmOptions[i].type == xrm_String )
{
*xrmOptions[i].str = ( char * ) allocate ( xrmValue.size * sizeof ( char ) );
strncpy ( *xrmOptions[i].str, xrmValue.addr, xrmValue.size );
} else if ( xrmOptions[i].type == xrm_Number ) {
}
else if ( xrmOptions[i].type == xrm_Number )
{
*xrmOptions[i].num = strtol ( xrmValue.addr, NULL, 10 );
}
}
@ -100,5 +108,4 @@ void parse_xresource_options( Display *display )
free ( class );
}
}
}