rofi/source/rofi.c

1219 lines
39 KiB
C
Raw Normal View History

/**
2014-03-01 16:27:52 +00:00
* rofi
2014-01-10 09:35:38 +00:00
*
* MIT/X11 License
* Copyright (c) 2012 Sean Pringle <sean.pringle@gmail.com>
2017-01-03 16:59:28 +00:00
* Modified 2013-2017 Qball Cow <qball@gmpclient.org>
2014-01-10 09:35:38 +00:00
*
* 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:
2014-01-10 09:35:38 +00:00
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
2014-01-10 09:35:38 +00:00
*
* 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 G_LOG_DOMAIN "Rofi"
#include <config.h>
2012-06-29 17:10:13 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2014-06-05 15:48:25 +00:00
#include <stdint.h>
2014-01-21 13:56:25 +00:00
#include <errno.h>
2014-03-16 12:47:44 +00:00
#include <time.h>
#include <locale.h>
#include <gmodule.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
2016-02-27 16:42:50 +00:00
#include <xcb/xcb_ewmh.h>
#include <xcb/xkb.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <xkbcommon/xkbcommon-x11.h>
#include <sys/types.h>
2014-03-18 09:55:25 +00:00
2016-01-18 19:51:35 +00:00
#include <glib-unix.h>
#include <libgwater-xcb.h>
2016-03-01 17:11:55 +00:00
#include "xcb-internal.h"
#include "xkb-internal.h"
2015-09-13 15:29:50 +00:00
2016-01-07 15:01:56 +00:00
#include "settings.h"
#include "mode.h"
2015-02-14 18:42:04 +00:00
#include "rofi.h"
2015-01-30 20:55:31 +00:00
#include "helper.h"
#include "widgets/textbox.h"
2015-02-09 18:35:51 +00:00
#include "x11-helper.h"
#include "xrmoptions.h"
2015-08-31 05:57:29 +00:00
#include "dialogs/dialogs.h"
2015-09-19 10:21:30 +00:00
2016-02-07 11:31:17 +00:00
#include "view.h"
#include "view-internal.h"
2016-03-12 13:00:19 +00:00
#include "gitconfig.h"
2016-12-09 18:49:49 +00:00
#include "theme.h"
#include "timings.h"
2017-03-29 18:18:41 +00:00
#include "default-theme.h"
2017-02-14 17:12:07 +00:00
// Plugin abi version.
// TODO: move this check to mode.c
#include "mode-private.h"
// Pidfile.
2016-10-26 06:24:34 +00:00
char *pidfile = NULL;
const char *cache_dir = NULL;
2017-01-09 21:40:11 +00:00
/** List of error messages.*/
2017-01-09 17:32:26 +00:00
GList *list_of_error_msgs = NULL;
2017-03-04 11:00:59 +00:00
static void rofi_collect_modi_destroy ( void );
2017-01-09 17:32:26 +00:00
void rofi_add_error_message ( GString *str )
{
list_of_error_msgs = g_list_append ( list_of_error_msgs, str );
}
/** global structure holding the keyboard status */
2016-10-26 06:24:34 +00:00
struct xkb_stuff xkb = {
2016-03-02 17:07:59 +00:00
.xcb_connection = NULL,
.context = NULL,
.keymap = NULL,
.state = NULL,
.compose = {
2016-10-15 18:00:26 +00:00
.table = NULL,
.state = NULL
}
2016-03-02 17:07:59 +00:00
};
/** Path to the configuration file */
char *config_path = NULL;
/** Array holding all activated modi. */
Mode **modi = NULL;
/** List of (possibly uninitialized) modi's */
Mode ** available_modi = NULL;
/** Length of #num_available_modi */
unsigned int num_available_modi = 0;
/** Number of activated modi in #modi array */
2016-10-26 06:24:34 +00:00
unsigned int num_modi = 0;
/** Current selected mode */
2016-10-26 06:24:34 +00:00
unsigned int curr_switcher = 0;
2015-09-26 18:34:34 +00:00
/** Glib main loop. */
2016-10-26 06:24:34 +00:00
GMainLoop *main_loop = NULL;
/** GWater xcb source, signalling events from the X server */
2016-10-26 06:24:34 +00:00
GWaterXcbSource *main_loop_source = NULL;
/** Flag indicating we are in dmenu mode. */
2016-10-26 06:24:34 +00:00
static int dmenu_mode = FALSE;
/** Rofi's return code */
2016-10-26 06:24:34 +00:00
int return_code = EXIT_SUCCESS;
2016-02-19 18:29:06 +00:00
void process_result ( RofiViewState *state );
2016-02-19 18:29:06 +00:00
void rofi_set_return_code ( int code )
{
return_code = code;
}
unsigned int rofi_get_num_enabled_modi ( void )
{
return num_modi;
}
const Mode * rofi_get_mode ( unsigned int index )
{
return modi[index];
}
/**
* @param name Name of the switcher to lookup.
*
* Find the index of the switcher with name.
*
* @returns index of the switcher in modi, -1 if not found.
*/
static int switcher_get ( const char *name )
{
for ( unsigned int i = 0; i < num_modi; i++ ) {
2016-02-06 12:40:25 +00:00
if ( strcmp ( mode_get_name ( modi[i] ), name ) == 0 ) {
return i;
}
}
return -1;
}
2015-01-08 12:16:44 +00:00
/**
* Do needed steps to start showing the gui
2015-01-08 12:16:44 +00:00
*/
static int setup ()
{
// Create pid file
int pfd = create_pid_file ( pidfile );
if ( pfd >= 0 ) {
// Request truecolor visual.
2016-03-01 17:11:55 +00:00
x11_create_visual_and_colormap ( );
textbox_setup ();
}
return pfd;
}
2016-02-06 13:27:36 +00:00
/**
* Teardown the gui.
*/
static void teardown ( int pfd )
{
g_debug ( "Teardown" );
// Cleanup font setup.
2015-01-21 09:04:15 +00:00
textbox_cleanup ( );
2015-07-28 20:22:18 +00:00
// Release the window.
2016-03-01 17:11:55 +00:00
release_keyboard ( );
2016-05-09 06:47:28 +00:00
release_pointer ( );
2016-02-06 13:27:36 +00:00
// Cleanup view
rofi_view_cleanup ();
2015-07-28 20:22:18 +00:00
// Cleanup pid file.
remove_pid_file ( pfd );
}
static void run_switcher ( ModeMode mode )
2014-01-20 21:58:10 +00:00
{
// Otherwise check if requested mode is enabled.
for ( unsigned int i = 0; i < num_modi; i++ ) {
2016-02-06 12:40:25 +00:00
if ( !mode_init ( modi[i] ) ) {
GString *str = g_string_new ( "Failed to initialize the mode: " );
2017-03-31 15:47:04 +00:00
g_string_append ( str, modi[i]->name );
g_string_append ( str, "\n" );
2017-03-31 15:47:04 +00:00
rofi_view_error_dialog ( str->str, ERROR_MSG_MARKUP );
g_string_free ( str, FALSE );
break;
}
2015-03-27 19:28:53 +00:00
}
// Error dialog must have been created.
if ( rofi_view_get_active () != NULL ) {
return;
}
curr_switcher = mode;
RofiViewState * state = rofi_view_create ( modi[mode], config.filter, MENU_PROMPT_COLON, process_result );
if ( state ) {
rofi_view_set_active ( state );
}
if ( rofi_view_get_active () == NULL ) {
g_main_loop_quit ( main_loop );
}
}
2016-02-19 18:29:06 +00:00
void process_result ( RofiViewState *state )
{
2016-02-19 18:29:06 +00:00
Mode *sw = state->sw;
rofi_view_set_active ( NULL );
2016-02-19 18:29:06 +00:00
if ( sw != NULL ) {
unsigned int selected_line = rofi_view_get_selected_line ( state );;
MenuReturn mretv = rofi_view_get_return_value ( state );
char *input = g_strdup ( rofi_view_get_user_input ( state ) );
ModeMode retv = mode_result ( sw, mretv, &input, selected_line );
g_free ( input );
2016-02-19 18:29:06 +00:00
ModeMode mode = curr_switcher;
2016-02-19 18:29:06 +00:00
// Find next enabled
if ( retv == NEXT_DIALOG ) {
mode = ( mode + 1 ) % num_modi;
}
else if ( retv == PREVIOUS_DIALOG ) {
if ( mode == 0 ) {
mode = num_modi - 1;
}
else {
mode = ( mode - 1 ) % num_modi;
}
}
else if ( retv == RELOAD_DIALOG ) {
// do nothing.
}
else if ( retv == RESET_DIALOG ) {
rofi_view_clear_input ( state );
}
2016-02-19 18:29:06 +00:00
else if ( retv < MODE_EXIT ) {
mode = ( retv ) % num_modi;
2015-03-27 19:28:53 +00:00
}
else {
2016-02-19 18:29:06 +00:00
mode = retv;
2015-03-27 19:28:53 +00:00
}
2016-02-19 18:29:06 +00:00
if ( mode != MODE_EXIT ) {
/**
* Load in the new mode.
*/
rofi_view_switch_mode ( state, modi[mode] );
rofi_view_set_active ( state );
curr_switcher = mode;
return;
2016-02-19 18:29:06 +00:00
}
}
2016-02-19 18:29:06 +00:00
rofi_view_free ( state );
2012-06-29 17:10:13 +00:00
}
/**
2015-10-21 07:42:55 +00:00
* Help function.
*/
static void print_main_application_options ( int is_term )
2015-10-21 07:42:55 +00:00
{
print_help_msg ( "-no-config", "", "Do not load configuration, use default values.", NULL, is_term );
print_help_msg ( "-v,-version", "", "Print the version number and exit.", NULL, is_term );
print_help_msg ( "-dmenu", "", "Start in dmenu mode.", NULL, is_term );
print_help_msg ( "-display", "[string]", "X server to contact.", "${DISPLAY}", is_term );
print_help_msg ( "-h,-help", "", "This help message.", NULL, is_term );
print_help_msg ( "-dump-xresources", "", "Dump the current configuration in Xresources format and exit.", NULL, is_term );
2015-12-10 17:20:04 +00:00
print_help_msg ( "-dump-xresources-theme", "", "Dump the current color scheme in Xresources format and exit.", NULL, is_term );
print_help_msg ( "-e", "[string]", "Show a dialog displaying the passed message and exit.", NULL, is_term );
print_help_msg ( "-markup", "", "Enable pango markup where possible.", NULL, is_term );
print_help_msg ( "-normal-window", "", "In dmenu mode, behave as a normal window. (experimental)", NULL, is_term );
2015-11-14 18:59:56 +00:00
print_help_msg ( "-show", "[mode]", "Show the mode 'mode' and exit. The mode has to be enabled.", NULL, is_term );
2017-02-02 18:00:45 +00:00
print_help_msg ( "-no-lazy-grab", "", "Disable lazy grab that, when fail to grab keyboard, does not block but retry later.", NULL, is_term );
2015-10-21 07:42:55 +00:00
}
static void help ( G_GNUC_UNUSED int argc, char **argv )
{
int is_term = isatty ( fileno ( stdout ) );
printf ( "%s usage:\n", argv[0] );
printf ( "\t%s [-options ...]\n\n", argv[0] );
2015-10-21 16:58:01 +00:00
printf ( "Command line only options:\n" );
print_main_application_options ( is_term );
2015-10-21 16:58:01 +00:00
printf ( "DMENU command line options:\n" );
print_dmenu_options ();
printf ( "Global options:\n" );
print_options ();
printf ( "\n" );
x11_dump_monitor_layout ();
printf("\n");
printf("Detected modi:\n");
for ( unsigned int i = 0; i < num_available_modi; i++ ) {
gboolean active = FALSE;
for ( unsigned int j = 0; j < num_modi; j++ ) {
if ( modi[j] == available_modi[i] ) {
active = TRUE;
break;
}
}
printf ( " * %s%s%s%s\n",
active?"+":"" ,
is_term ? (active?color_green:color_red) : "",
available_modi[i]->name,
is_term ? color_reset : ""
);
}
printf ( "\n" );
printf ( "Compile time options:\n" );
#ifdef WINDOW_MODE
printf ( "\t* window %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
#else
printf ( "\t* window %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
#endif
#ifdef ENABLE_DRUN
printf ( "\t* drun %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
#else
printf ( "\t* drun %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
#endif
#ifdef TIMINGS
printf ( "\t* timings %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
#else
printf ( "\t* timings %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
#endif
#ifdef ENABLE_GCOV
printf ( "\t* gcov %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
#else
printf ( "\t* gcov %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
#endif
#ifdef ENABLE_ASAN
printf ( "\t* asan %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
#else
printf ( "\t* asan %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
#endif
printf ( "\n" );
printf ( "For more information see: %sman rofi%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
2016-03-12 13:00:19 +00:00
#ifdef GIT_VERSION
printf ( " Version: %s"GIT_VERSION "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
#else
printf ( " Version: %s"VERSION "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
2016-03-12 13:00:19 +00:00
#endif
printf ( " Bugreports: %s"PACKAGE_BUGREPORT "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
printf ( " Support: %s"PACKAGE_URL "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
printf ( " %s#rofi @ freenode.net%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
if ( find_arg ( "-no-config" ) < 0 ) {
printf ( " Configuration file: %s%s%s\n", is_term ? color_bold : "", config_path, is_term ? color_reset : "" );
}
else {
printf ( " Configuration file: %sDisabled%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
}
}
static void help_print_disabled_mode ( const char *mode )
{
int is_term = isatty ( fileno ( stdout ) );
// Only output to terminal
if ( is_term ) {
g_warning ( "Mode %s%s%s is not enabled. I have enabled it for now.",
color_red, mode, color_reset );
g_warning ( "Please consider adding %s%s%s to the list of enabled modi: %smodi: %s%s%s,%s%s.",
color_red, mode, color_reset,
color_green, config.modi, color_reset,
color_red, mode, color_reset
);
}
}
static void help_print_no_arguments ( void )
{
int is_term = isatty ( fileno ( stdout ) );
// Daemon mode
fprintf ( stderr, "Rofi is unsure what to show.\n" );
fprintf ( stderr, "Please specify the mode you want to show.\n\n" );
fprintf ( stderr, " %srofi%s -show %s{mode}%s\n\n",
is_term ? color_bold : "", is_term ? color_reset : "",
is_term ? color_green : "", is_term ? color_reset : "" );
fprintf ( stderr, "The following modi are enabled:\n" );
for ( unsigned int j = 0; j < num_modi; j++ ) {
fprintf ( stderr, " * %s%s%s\n",
is_term ? color_green : "",
modi[j]->name,
is_term ? color_reset : "" );
}
fprintf ( stderr, "\nThe following can be enabled:\n" );
for ( unsigned int i = 0; i < num_available_modi; i++ ) {
gboolean active = FALSE;
for ( unsigned int j = 0; j < num_modi; j++ ) {
if ( modi[j] == available_modi[i] ) {
active = TRUE;
break;
}
}
if ( !active ) {
fprintf ( stderr, " * %s%s%s\n",
is_term ? color_red : "",
available_modi[i]->name,
is_term ? color_reset : "" );
}
}
fprintf ( stderr, "\nTo activate a mode, add it to the list of modi in the %smodi%s setting.",
is_term ? color_green : "", is_term ? color_reset : "" );
}
2014-09-23 07:24:24 +00:00
/**
* Cleanup globally allocated memory.
*/
2014-05-19 19:58:13 +00:00
static void cleanup ()
2014-05-19 19:02:05 +00:00
{
for ( unsigned int i = 0; i < num_modi; i++ ) {
mode_destroy ( modi[i] );
}
2016-02-10 18:40:19 +00:00
rofi_view_workers_finalize ();
if ( main_loop != NULL ) {
2016-02-06 12:06:58 +00:00
if ( main_loop_source ) {
g_water_xcb_source_free ( main_loop_source );
2016-01-27 22:49:56 +00:00
}
g_main_loop_unref ( main_loop );
main_loop = NULL;
}
2016-08-22 06:39:22 +00:00
// XKB Cleanup
//
if ( xkb.compose.state != NULL ) {
xkb_compose_state_unref ( xkb.compose.state );
xkb.compose.state = NULL;
}
if ( xkb.compose.table != NULL ) {
xkb_compose_table_unref ( xkb.compose.table );
xkb.compose.table = NULL;
}
if ( xkb.state != NULL ) {
xkb_state_unref ( xkb.state );
xkb.state = NULL;
}
if ( xkb.keymap != NULL ) {
xkb_keymap_unref ( xkb.keymap );
xkb.keymap = NULL;
}
if ( xkb.context != NULL ) {
xkb_context_unref ( xkb.context );
xkb.context = NULL;
}
2014-05-19 19:02:05 +00:00
// Cleanup
2016-03-01 17:33:26 +00:00
xcb_stuff_wipe ( xcb );
2016-08-22 06:39:22 +00:00
2014-05-19 19:58:13 +00:00
// Cleaning up memory allocated by the Xresources file.
2015-02-03 07:21:59 +00:00
config_xresource_free ();
for ( unsigned int i = 0; i < num_modi; i++ ) {
2016-02-06 12:40:25 +00:00
mode_free ( &( modi[i] ) );
}
g_free ( modi );
2015-04-30 20:42:04 +00:00
// Cleanup the custom keybinding
cleanup_abe ();
g_free ( config_path );
2017-01-09 17:32:26 +00:00
if ( list_of_error_msgs ) {
for ( GList *iter = g_list_first ( list_of_error_msgs );
2017-01-09 21:40:11 +00:00
iter != NULL; iter = g_list_next ( iter ) ) {
g_string_free ( (GString *) iter->data, TRUE );
2017-01-09 17:32:26 +00:00
}
g_list_free ( list_of_error_msgs );
}
if ( rofi_theme ) {
rofi_theme_free ( rofi_theme );
rofi_theme = NULL;
}
2015-11-24 21:53:40 +00:00
TIMINGS_STOP ();
2017-03-04 11:00:59 +00:00
rofi_collect_modi_destroy ( );
}
/**
* Collected modi
*/
/**
* @param name Search for mode with this name.
*
* @return returns Mode * when found, NULL if not.
*/
Mode * rofi_collect_modi_search ( const char *name )
{
2017-03-04 18:41:06 +00:00
for ( unsigned int i = 0; i < num_available_modi; i++ ) {
2017-03-04 11:00:59 +00:00
if ( g_strcmp0 ( name, available_modi[i]->name ) == 0 ) {
return available_modi[i];
}
}
return NULL;
}
/**
* @param mode Add mode to list.
*
* @returns TRUE when success.
*/
static gboolean rofi_collect_modi_add ( Mode *mode )
{
Mode *m = rofi_collect_modi_search ( mode->name );
if ( m == NULL ) {
2017-03-04 18:41:06 +00:00
available_modi = g_realloc ( available_modi, sizeof ( Mode * ) * ( num_available_modi + 1 ) );
2017-03-04 11:00:59 +00:00
// Set mode.
available_modi[num_available_modi] = mode;
num_available_modi++;
return TRUE;
}
return FALSE;
}
2017-03-04 11:22:28 +00:00
static void rofi_collect_modi_dir ( const char *base_dir )
{
GDir *dir = g_dir_open ( base_dir, 0, NULL );
2017-03-04 11:00:59 +00:00
if ( dir ) {
const char *dn = NULL;
2017-03-04 18:41:06 +00:00
while ( ( dn = g_dir_read_name ( dir ) ) ) {
2017-03-04 11:00:59 +00:00
if ( !g_str_has_suffix ( dn, G_MODULE_SUFFIX ) ) {
continue;
}
2017-03-04 18:41:06 +00:00
char *fn = g_build_filename ( PLUGIN_PATH, dn, NULL );
GModule *mod = g_module_open ( fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
2017-03-04 11:00:59 +00:00
if ( mod ) {
Mode *m = NULL;
2017-03-04 18:41:06 +00:00
if ( g_module_symbol ( mod, "mode", (gpointer *) &m ) ) {
2017-03-04 11:00:59 +00:00
if ( m->abi_version != ABI_VERSION ) {
g_warning ( "ABI version of plugin does not match: %08X expecting: %08X", m->abi_version, ABI_VERSION );
2017-03-04 11:00:59 +00:00
g_module_close ( mod );
2017-03-04 18:41:06 +00:00
}
else {
2017-03-04 11:00:59 +00:00
m->module = mod;
2017-03-04 18:41:06 +00:00
if ( !rofi_collect_modi_add ( m ) ) {
2017-03-04 11:00:59 +00:00
g_module_close ( mod );
}
}
2017-03-04 18:41:06 +00:00
}
else {
g_warning ( "Symbol 'mode' not found in module: %s", fn );
2017-03-04 11:00:59 +00:00
g_module_close ( mod );
}
}
g_free ( fn );
}
g_dir_close ( dir );
}
}
2017-03-04 11:22:28 +00:00
/**
* Find all available modi.
*/
static void rofi_collect_modi ( void )
{
#ifdef WINDOW_MODE
rofi_collect_modi_add ( &window_mode );
rofi_collect_modi_add ( &window_mode_cd );
#endif
rofi_collect_modi_add ( &run_mode );
rofi_collect_modi_add ( &ssh_mode );
#ifdef ENABLE_DRUN
rofi_collect_modi_add ( &drun_mode );
#endif
rofi_collect_modi_add ( &combi_mode );
rofi_collect_modi_add ( &help_keys_mode );
rofi_collect_modi_dir ( PLUGIN_PATH );
}
2017-03-04 11:00:59 +00:00
/**
* Setup configuration for config.
*/
static void rofi_collect_modi_setup ( void )
{
2017-03-04 18:41:06 +00:00
for ( unsigned int i = 0; i < num_available_modi; i++ ) {
mode_set_config ( available_modi[i] );
2017-03-04 11:00:59 +00:00
}
}
static void rofi_collect_modi_destroy ( void )
{
2017-03-04 18:41:06 +00:00
for ( unsigned int i = 0; i < num_available_modi; i++ ) {
2017-03-04 11:00:59 +00:00
if ( available_modi[i]->module ) {
g_module_close ( available_modi[i]->module );
}
}
g_free ( available_modi );
2017-03-04 18:41:06 +00:00
available_modi = NULL;
2017-03-04 11:00:59 +00:00
num_available_modi = 0;
2014-05-19 19:02:05 +00:00
}
2014-05-20 09:41:39 +00:00
2014-09-23 07:24:24 +00:00
/**
* Parse the switcher string, into internal array of type Mode.
2014-09-23 07:24:24 +00:00
*
* String is split on separator ','
* First the three build-in modi are checked: window, run, ssh
* if that fails, a script-switcher is created.
*/
2016-02-04 08:20:10 +00:00
static int add_mode ( const char * token )
{
unsigned int index = num_modi;
// Resize and add entry.
2016-02-06 12:40:25 +00:00
modi = (Mode * *) g_realloc ( modi, sizeof ( Mode* ) * ( num_modi + 1 ) );
2016-02-04 08:20:10 +00:00
2017-03-04 11:00:59 +00:00
Mode *mode = rofi_collect_modi_search ( token );
if ( mode ) {
modi[num_modi] = mode;
2016-02-04 08:20:10 +00:00
num_modi++;
2017-03-04 18:41:06 +00:00
}
else {
2016-02-04 08:20:10 +00:00
// If not build in, use custom modi.
Mode *sw = script_switcher_parse_setup ( token );
if ( sw != NULL ) {
2016-02-06 12:40:25 +00:00
modi[num_modi] = sw;
2016-02-04 08:20:10 +00:00
num_modi++;
2017-03-04 18:41:06 +00:00
}
else {
2016-02-04 08:20:10 +00:00
// Report error, don't continue.
g_warning ( "Invalid script mode: %s", token );
2016-02-04 08:20:10 +00:00
}
}
return ( index == num_modi ) ? -1 : (int) index;
}
static void setup_modi ( void )
{
2017-03-31 18:57:42 +00:00
const char *const sep = ",#";
char *savept = NULL;
2015-01-08 12:16:44 +00:00
// Make a copy, as strtok will modify it.
char *switcher_str = g_strdup ( config.modi );
// Split token on ','. This modifies switcher_str.
for ( char *token = strtok_r ( switcher_str, sep, &savept ); token != NULL; token = strtok_r ( NULL, sep, &savept ) ) {
2016-02-04 08:20:10 +00:00
add_mode ( token );
}
// Free string that was modified by strtok_r
g_free ( switcher_str );
}
2015-08-01 14:10:52 +00:00
/**
* Process X11 events in the main-loop (gui-thread) of the application.
*/
static void main_loop_x11_event_handler_view ( xcb_generic_event_t *ev )
{
RofiViewState *state = rofi_view_get_active ();
if ( state != NULL ) {
rofi_view_itterrate ( state, ev, &xkb );
if ( rofi_view_get_completed ( state ) ) {
// This menu is done.
rofi_view_finalize ( state );
// cleanup
if ( rofi_view_get_active () == NULL ) {
g_main_loop_quit ( main_loop );
}
}
}
}
static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data )
2015-08-01 14:10:52 +00:00
{
if ( ev == NULL ) {
int status = xcb_connection_has_error ( xcb->connection );
2017-04-14 02:14:08 +00:00
if(status > 0) {
g_warning ( "The XCB connection to X server had a fatal error: %d", status );
2017-04-14 02:14:08 +00:00
g_main_loop_quit ( main_loop );
return G_SOURCE_REMOVE;
} else {
g_warning ( "main_loop_x11_event_handler: ev == NULL, status == %d", status );
2017-04-14 02:14:08 +00:00
return G_SOURCE_CONTINUE;
}
}
uint8_t type = ev->response_type & ~0x80;
if ( type == xkb.first_event ) {
switch ( ev->pad0 )
{
case XCB_XKB_MAP_NOTIFY:
xkb_state_unref ( xkb.state );
xkb_keymap_unref ( xkb.keymap );
xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, 0 );
xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id );
break;
case XCB_XKB_STATE_NOTIFY:
2016-10-15 18:00:26 +00:00
{
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
guint modmask;
xkb_state_update_mask ( xkb.state,
ksne->baseMods,
ksne->latchedMods,
ksne->lockedMods,
ksne->baseGroup,
ksne->latchedGroup,
ksne->lockedGroup );
modmask = x11_get_current_mask ( &xkb );
if ( modmask == 0 ) {
abe_trigger_release ( );
// Because of abe_trigger, state of rofi can be changed. handle this!
// Run mainloop on dummy event.
2016-12-15 08:17:39 +00:00
xcb_generic_event_t dev;
dev.response_type = 0;
main_loop_x11_event_handler_view ( &dev );
}
2016-10-15 18:00:26 +00:00
break;
}
}
return G_SOURCE_CONTINUE;
}
2016-03-01 17:11:55 +00:00
if ( xcb->sndisplay != NULL ) {
sn_xcb_display_process_event ( xcb->sndisplay, ev );
}
main_loop_x11_event_handler_view ( ev );
2016-01-18 20:43:33 +00:00
return G_SOURCE_CONTINUE;
2015-08-01 14:10:52 +00:00
}
2016-01-19 07:10:17 +00:00
static gboolean main_loop_signal_handler_int ( G_GNUC_UNUSED gpointer data )
2016-01-18 19:51:35 +00:00
{
// Break out of loop.
g_main_loop_quit ( main_loop );
return G_SOURCE_CONTINUE;
}
/** X server error depth. to handle nested errors. */
2016-01-18 19:51:35 +00:00
static int error_trap_depth = 0;
2016-02-27 23:15:42 +00:00
static void error_trap_push ( G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED xcb_connection_t *xdisplay )
2016-01-18 19:51:35 +00:00
{
++error_trap_depth;
}
2016-02-27 23:15:42 +00:00
static void error_trap_pop ( G_GNUC_UNUSED SnDisplay *display, xcb_connection_t *xdisplay )
2015-09-13 15:29:50 +00:00
{
if ( error_trap_depth == 0 ) {
g_warning ( "Error trap underflow!" );
2015-11-14 18:52:15 +00:00
exit ( EXIT_FAILURE );
2015-09-13 15:29:50 +00:00
}
2016-02-28 14:32:53 +00:00
xcb_flush ( xdisplay );
2015-09-13 15:29:50 +00:00
--error_trap_depth;
}
2017-01-08 15:23:17 +00:00
/** Retry count of grabbing keyboard. */
unsigned int lazy_grab_retry_count_kb = 0;
2017-01-08 15:23:17 +00:00
/** Retry count of grabbing pointer. */
unsigned int lazy_grab_retry_count_pt = 0;
static gboolean lazy_grab_pointer ( G_GNUC_UNUSED gpointer data )
{
// After 5 sec.
if ( lazy_grab_retry_count_pt > ( 5 * 1000 ) ) {
g_warning ( "Failed to grab pointer after %u times. Giving up.", lazy_grab_retry_count_pt );
return G_SOURCE_REMOVE;
}
if ( take_pointer ( xcb_stuff_get_root_window ( xcb ), 0 ) ) {
return G_SOURCE_REMOVE;
}
lazy_grab_retry_count_pt++;
return G_SOURCE_CONTINUE;
}
static gboolean lazy_grab_keyboard ( G_GNUC_UNUSED gpointer data )
{
// After 5 sec.
if ( lazy_grab_retry_count_kb > ( 5 * 1000 ) ) {
g_warning ( "Failed to grab keyboard after %u times. Giving up.", lazy_grab_retry_count_kb );
g_main_loop_quit ( main_loop );
return G_SOURCE_REMOVE;
}
if ( take_keyboard ( xcb_stuff_get_root_window ( xcb ), 0 ) ) {
return G_SOURCE_REMOVE;
}
2017-01-09 07:32:16 +00:00
lazy_grab_retry_count_kb++;
return G_SOURCE_CONTINUE;
}
2016-02-19 18:29:06 +00:00
static gboolean startup ( G_GNUC_UNUSED gpointer data )
{
2016-02-19 18:50:48 +00:00
TICK_N ( "Startup" );
2016-02-19 18:29:06 +00:00
// flags to run immediately and exit
char *sname = NULL;
char *msg = NULL;
MenuFlags window_flags = MENU_NORMAL;
if ( find_arg ( "-normal-window" ) >= 0 ) {
window_flags |= MENU_NORMAL_WINDOW;
}
/**
* Create window (without showing)
*/
// Try to grab the keyboard as early as possible.
// We grab this using the rootwindow (as dmenu does it).
// this seems to result in the smallest delay for most people.
if ( ( window_flags & MENU_NORMAL_WINDOW ) == 0 ) {
2017-02-02 18:00:45 +00:00
if ( find_arg ( "-no-lazy-grab" ) >= 0 ) {
if ( !take_keyboard ( xcb_stuff_get_root_window ( xcb ), 500 ) ) {
g_warning ( "Failed to grab keyboard, even after %d uS.", 500 * 1000 );
g_main_loop_quit ( main_loop );
return G_SOURCE_REMOVE;
}
if ( !take_pointer ( xcb_stuff_get_root_window ( xcb ), 100 ) ) {
g_warning ( "Failed to grab mouse pointer, even after %d uS.", 100 * 1000 );
}
}
2017-02-02 18:00:45 +00:00
else {
if ( !take_keyboard ( xcb_stuff_get_root_window ( xcb ), 0 ) ) {
g_timeout_add ( 1, lazy_grab_keyboard, NULL );
}
if ( !take_pointer ( xcb_stuff_get_root_window ( xcb ), 0 ) ) {
g_timeout_add ( 1, lazy_grab_pointer, NULL );
}
}
}
TICK_N ( "Grab keyboard" );
__create_window ( window_flags );
TICK_N ( "Create Window" );
2016-02-19 18:50:48 +00:00
// Parse the keybindings.
if ( !parse_keys_abe () ) {
// Error dialog
2016-02-19 18:50:48 +00:00
return G_SOURCE_REMOVE;
}
TICK_N ( "Parse ABE" );
// Sanity check
2017-01-09 17:32:26 +00:00
config_sanity_check ( );
TICK_N ( "Config sanity check" );
if ( list_of_error_msgs != NULL ) {
2017-01-09 21:40:11 +00:00
GString *emesg = g_string_new ( "The following errors where detected when starting rofi:\n" );
GList *iter = g_list_first ( list_of_error_msgs );
int index = 0;
for (; iter != NULL && index < 2; iter = g_list_next ( iter ) ) {
GString *msg = (GString *) ( iter->data );
g_string_append ( emesg, "\n\n" );
2017-01-09 17:32:26 +00:00
g_string_append ( emesg, msg->str );
2017-01-09 21:40:11 +00:00
index++;
2017-01-09 17:32:26 +00:00
}
2017-01-09 21:40:11 +00:00
if ( g_list_length ( iter ) > 1 ) {
g_string_append_printf ( emesg, "\nThere are <b>%d</b> more errors.", g_list_length ( iter ) - 1 );
}
2017-01-09 17:32:26 +00:00
rofi_view_error_dialog ( emesg->str, ERROR_MSG_MARKUP );
g_string_free ( emesg, TRUE );
return G_SOURCE_REMOVE;
}
2016-02-19 18:29:06 +00:00
// Dmenu mode.
if ( dmenu_mode == TRUE ) {
// force off sidebar mode:
config.sidebar_mode = FALSE;
int retv = dmenu_switcher_dialog ();
2016-02-19 18:29:06 +00:00
if ( retv ) {
2016-02-19 18:50:48 +00:00
rofi_set_return_code ( EXIT_SUCCESS );
2016-02-19 18:29:06 +00:00
// Directly exit.
2016-02-19 18:50:48 +00:00
g_main_loop_quit ( main_loop );
2016-02-19 18:29:06 +00:00
}
}
else if ( find_arg_str ( "-e", &( msg ) ) ) {
int markup = FALSE;
if ( find_arg ( "-markup" ) >= 0 ) {
markup = TRUE;
}
if ( !rofi_view_error_dialog ( msg, markup ) ) {
2016-03-03 07:21:28 +00:00
g_main_loop_quit ( main_loop );
}
2016-02-19 18:29:06 +00:00
}
else if ( find_arg_str ( "-show", &sname ) == TRUE ) {
int index = switcher_get ( sname );
if ( index < 0 ) {
// Add it to the list
index = add_mode ( sname );
// Complain
if ( index >= 0 ) {
help_print_disabled_mode ( sname );
2016-02-19 18:29:06 +00:00
}
// Run it anyway if found.
}
if ( index >= 0 ) {
run_switcher ( index );
}
else {
g_warning ( "The %s mode has not been enabled", sname );
g_main_loop_quit ( main_loop );
2016-02-19 18:29:06 +00:00
return G_SOURCE_REMOVE;
}
}
else if ( find_arg ( "-show" ) >= 0 && num_modi > 0 ) {
run_switcher ( 0 );
}
2016-02-19 18:29:06 +00:00
else{
help_print_no_arguments ( );
g_main_loop_quit ( main_loop );
2016-02-19 18:29:06 +00:00
}
return G_SOURCE_REMOVE;
}
/**
* @param argc number of input arguments.
* @param argv array of the input arguments.
*
* Main application entry point.
*
* @returns return code of rofi.
*/
2014-05-22 07:33:32 +00:00
int main ( int argc, char *argv[] )
{
2015-11-24 21:53:40 +00:00
TIMINGS_START ();
2015-03-11 17:32:37 +00:00
cmd_set_arguments ( argc, argv );
2015-02-03 07:21:59 +00:00
// Version
2015-03-11 17:32:37 +00:00
if ( find_arg ( "-v" ) >= 0 || find_arg ( "-version" ) >= 0 ) {
2016-03-12 13:00:19 +00:00
#ifdef GIT_VERSION
g_print ( "Version: "GIT_VERSION "\n" );
#else
g_print ( "Version: "VERSION "\n" );
2016-03-12 13:00:19 +00:00
#endif
return EXIT_SUCCESS;
2015-02-03 07:21:59 +00:00
}
// Detect if we are in dmenu mode.
// This has two possible causes.
// 1 the user specifies it on the command-line.
2015-03-11 17:32:37 +00:00
if ( find_arg ( "-dmenu" ) >= 0 ) {
dmenu_mode = TRUE;
}
// 2 the binary that executed is called dmenu (e.g. symlink to rofi)
else{
// Get the base name of the executable called.
char *base_name = g_path_get_basename ( argv[0] );
const char * const dmenu_str = "dmenu";
dmenu_mode = ( strcmp ( base_name, dmenu_str ) == 0 );
// Free the basename for dmenu detection.
g_free ( base_name );
}
2015-11-24 21:53:40 +00:00
TICK ();
2014-05-20 09:41:39 +00:00
// Get the path to the cache dir.
cache_dir = g_get_user_cache_dir ();
if ( g_mkdir_with_parents ( cache_dir, 0700 ) < 0 ) {
g_warning ( "Failed to create cache directory: %s", g_strerror ( errno ) );
return EXIT_FAILURE;
}
// Create pid file path.
const char *path = g_get_user_runtime_dir ();
if ( path ) {
if ( g_mkdir_with_parents ( path, 0700 ) < 0 ) {
g_warning ( "Failed to create user runtime directory: %s with error: %s", path, g_strerror ( errno ) );
pidfile = g_build_filename ( g_get_home_dir (), ".rofi.pid", NULL );
}
else {
pidfile = g_build_filename ( path, "rofi.pid", NULL );
}
}
2015-10-16 06:42:01 +00:00
config_parser_add_option ( xrm_String, "pid", (void * *) &pidfile, "Pidfile location" );
if ( find_arg ( "-config" ) < 0 ) {
const char *cpath = g_get_user_config_dir ();
if ( cpath ) {
config_path = g_build_filename ( cpath, "rofi", "config", NULL );
}
}
else {
char *c = NULL;
find_arg_str ( "-config", &c );
config_path = rofi_expand_path ( c );
}
2015-11-24 21:53:40 +00:00
TICK ();
2015-11-22 20:10:39 +00:00
if ( setlocale ( LC_ALL, "" ) == NULL ) {
g_warning ( "Failed to set locale." );
cleanup ();
return EXIT_FAILURE;
}
2015-11-22 20:10:39 +00:00
2017-02-09 07:45:15 +00:00
// Get DISPLAY, first env, then argument.
// We never modify display_str content.
2017-03-04 18:41:06 +00:00
char *display_str = ( char *) g_getenv ( "DISPLAY" );
2017-02-09 07:45:15 +00:00
find_arg_str ( "-display", &display_str );
2016-03-01 17:11:55 +00:00
xcb->connection = xcb_connect ( display_str, &xcb->screen_nbr );
2016-03-03 14:59:31 +00:00
if ( xcb_connection_has_error ( xcb->connection ) ) {
g_warning( "Failed to open display: %s", display_str );
cleanup ();
2016-03-03 14:59:31 +00:00
return EXIT_FAILURE;
}
2017-03-04 11:00:59 +00:00
2015-11-24 21:53:40 +00:00
TICK_N ( "Open Display" );
2017-03-04 11:00:59 +00:00
rofi_collect_modi ();
rofi_collect_modi_setup ();
2017-03-04 11:00:59 +00:00
TICK_N ( "Collect MODI" );
2016-03-01 17:11:55 +00:00
xcb->screen = xcb_aux_get_screen ( xcb->connection, xcb->screen_nbr );
x11_build_monitor_layout ();
2016-03-04 07:02:54 +00:00
xcb_intern_atom_cookie_t *ac = xcb_ewmh_init_atoms ( xcb->connection, &xcb->ewmh );
2016-03-03 15:02:14 +00:00
xcb_generic_error_t *errors = NULL;
xcb_ewmh_init_atoms_replies ( &xcb->ewmh, ac, &errors );
2016-02-28 14:32:53 +00:00
if ( errors ) {
g_warning ( "Failed to create EWMH atoms" );
2016-03-04 07:02:54 +00:00
free ( errors );
2016-02-27 16:42:50 +00:00
}
// Discover the current active window manager.
2017-03-04 18:41:06 +00:00
x11_helper_discover_window_manager ();
2017-02-01 07:47:43 +00:00
TICK_N ( "Setup XCB" );
2016-02-27 16:42:50 +00:00
2016-03-01 17:11:55 +00:00
if ( xkb_x11_setup_xkb_extension ( xcb->connection, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, NULL, NULL, &xkb.first_event, NULL ) < 0 ) {
g_warning ( "cannot setup XKB extension!" );
cleanup ();
return EXIT_FAILURE;
}
xkb.context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS );
if ( xkb.context == NULL ) {
g_warning ( "cannot create XKB context!" );
cleanup ();
return EXIT_FAILURE;
}
2016-03-01 17:11:55 +00:00
xkb.xcb_connection = xcb->connection;
2016-03-01 17:11:55 +00:00
xkb.device_id = xkb_x11_get_core_keyboard_device_id ( xcb->connection );
enum
{
required_events =
( XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
XCB_XKB_EVENT_TYPE_STATE_NOTIFY ),
required_nkn_details =
( XCB_XKB_NKN_DETAIL_KEYCODES ),
required_map_parts =
( XCB_XKB_MAP_PART_KEY_TYPES |
XCB_XKB_MAP_PART_KEY_SYMS |
XCB_XKB_MAP_PART_MODIFIER_MAP |
XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
XCB_XKB_MAP_PART_KEY_ACTIONS |
XCB_XKB_MAP_PART_VIRTUAL_MODS |
XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP ),
required_state_details =
( XCB_XKB_STATE_PART_MODIFIER_BASE |
XCB_XKB_STATE_PART_MODIFIER_LATCH |
XCB_XKB_STATE_PART_MODIFIER_LOCK |
XCB_XKB_STATE_PART_GROUP_BASE |
XCB_XKB_STATE_PART_GROUP_LATCH |
XCB_XKB_STATE_PART_GROUP_LOCK ),
};
static const xcb_xkb_select_events_details_t details = {
.affectNewKeyboard = required_nkn_details,
.newKeyboardDetails = required_nkn_details,
.affectState = required_state_details,
.stateDetails = required_state_details,
};
2016-03-01 17:11:55 +00:00
xcb_xkb_select_events ( xcb->connection, xkb.device_id, required_events, /* affectWhich */
0, /* clear */
2016-03-04 07:02:54 +00:00
required_events, /* selectAll */
required_map_parts, /* affectMap */
required_map_parts, /* map */
&details );
2016-03-01 17:11:55 +00:00
xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, XKB_KEYMAP_COMPILE_NO_FLAGS );
if ( xkb.keymap == NULL ) {
g_warning ( "Failed to get Keymap for current keyboard device." );
cleanup ();
return EXIT_FAILURE;
}
xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id );
if ( xkb.state == NULL ) {
g_warning ( "Failed to get state object for current keyboard device." );
cleanup ();
return EXIT_FAILURE;
}
xkb.compose.table = xkb_compose_table_new_from_locale ( xkb.context, setlocale ( LC_CTYPE, NULL ), 0 );
2016-03-04 07:02:54 +00:00
if ( xkb.compose.table != NULL ) {
xkb.compose.state = xkb_compose_state_new ( xkb.compose.table, 0 );
}
else {
g_warning ( "Failed to get keyboard compose table. Trying to limp on." );
2016-03-03 23:22:04 +00:00
}
if ( xcb_connection_has_error ( xcb->connection ) ) {
g_warning ( "Connection has error" );
cleanup ();
return EXIT_FAILURE;
}
2016-03-01 17:11:55 +00:00
x11_setup ( &xkb );
2017-02-01 07:47:43 +00:00
TICK_N ( "Setup xkb" );
if ( xcb_connection_has_error ( xcb->connection ) ) {
g_warning ( "Connection has error" );
cleanup ();
return EXIT_FAILURE;
}
main_loop = g_main_loop_new ( NULL, FALSE );
TICK_N ( "Setup mainloop" );
2015-09-13 15:29:50 +00:00
// startup not.
2016-03-01 17:11:55 +00:00
xcb->sndisplay = sn_xcb_display_new ( xcb->connection, error_trap_push, error_trap_pop );
if ( xcb_connection_has_error ( xcb->connection ) ) {
g_warning ( "Connection has error" );
cleanup ();
return EXIT_FAILURE;
}
2015-09-13 15:29:50 +00:00
2016-03-01 17:11:55 +00:00
if ( xcb->sndisplay != NULL ) {
xcb->sncontext = sn_launchee_context_new_from_environment ( xcb->sndisplay, xcb->screen_nbr );
2015-09-13 15:29:50 +00:00
}
if ( xcb_connection_has_error ( xcb->connection ) ) {
g_warning ( "Connection has error" );
cleanup ();
return EXIT_FAILURE;
}
2015-11-24 21:53:40 +00:00
TICK_N ( "Startup Notification" );
2015-04-30 20:42:04 +00:00
// Setup keybinding
setup_abe ();
2015-11-24 21:53:40 +00:00
TICK_N ( "Setup abe" );
2015-04-30 20:42:04 +00:00
if ( find_arg ( "-no-config" ) < 0 ) {
// Load distro default settings
gchar *etc = g_build_filename ( SYSCONFDIR, "rofi.conf", NULL );
if ( g_file_test ( etc, G_FILE_TEST_IS_REGULAR ) ) {
config_parse_xresource_options_file ( etc );
}
g_free ( etc );
// Load in config from X resources.
config_parse_xresource_options ( xcb );
config_parse_xresource_options_file ( config_path );
2017-03-28 18:04:02 +00:00
find_arg_str ( "-theme", &( config.theme ) );
if ( config.theme ) {
TICK_N ( "Parse theme" );
if ( rofi_theme_parse_file ( config.theme ) ) {
// TODO: instantiate fallback theme.?
rofi_theme_free ( rofi_theme );
rofi_theme = NULL;
}
TICK_N ( "Parsed theme" );
}
}
// Parse command line for settings, independent of other -no-config.
config_parse_cmd_options ( );
TICK_N ( "Load cmd config " );
if ( !dmenu_mode ) {
// setup_modi
setup_modi ();
TICK_N ( "Setup Modi" );
}
const char ** theme_str = find_arg_strv ( "-theme-str" );
if ( theme_str ) {
for ( int index = 0; theme_str && theme_str[index]; index++ ) {
if ( rofi_theme_parse_string ( theme_str[index] ) ) {
rofi_theme_free ( rofi_theme );
rofi_theme = NULL;
}
}
g_free ( theme_str );
}
if ( rofi_theme_is_empty ( ) ) {
if ( rofi_theme_parse_string ( default_theme ) ) {
g_warning ( "Failed to parse default theme. Giving up.." );
if ( list_of_error_msgs ) {
for ( GList *iter = g_list_first ( list_of_error_msgs );
iter != NULL; iter = g_list_next ( iter ) ) {
g_warning ( "Error: %s%s%s",
color_bold, ( (GString *) iter->data )->str, color_reset );
}
}
2017-03-29 18:18:41 +00:00
rofi_theme = NULL;
cleanup ();
return EXIT_FAILURE;
}
rofi_theme_convert_old ();
}
if ( find_arg ( "-dump-theme" ) >= 0 ) {
rofi_theme_print ( rofi_theme );
cleanup ();
return EXIT_SUCCESS;
}
// Dump.
// catch help request
if ( find_arg ( "-h" ) >= 0 || find_arg ( "-help" ) >= 0 || find_arg ( "--help" ) >= 0 ) {
help ( argc, argv );
cleanup ();
return EXIT_SUCCESS;
}
2015-03-11 17:32:37 +00:00
if ( find_arg ( "-dump-xresources" ) >= 0 ) {
2016-01-07 12:32:33 +00:00
config_parse_xresource_dump ();
cleanup ();
return EXIT_SUCCESS;
}
2016-03-01 17:11:55 +00:00
main_loop_source = g_water_xcb_source_new_for_connection ( NULL, xcb->connection, main_loop_x11_event_handler, NULL, NULL );
2016-02-19 18:50:48 +00:00
TICK_N ( "X11 Setup " );
2014-08-27 17:44:15 +00:00
2016-02-10 18:40:19 +00:00
rofi_view_workers_initialize ();
// Setup signal handling sources.
2016-01-26 07:36:44 +00:00
// SIGINT
g_unix_signal_add ( SIGINT, main_loop_signal_handler_int, NULL );
2016-02-19 18:29:06 +00:00
g_idle_add ( startup, NULL );
2014-01-23 19:33:13 +00:00
// Pidfile + visuals
int pfd = setup ();
if ( pfd < 0 ) {
return EXIT_FAILURE;
}
// Start mainloop.
g_main_loop_run ( main_loop );
teardown ( pfd );
cleanup ();
2016-02-19 18:29:06 +00:00
return return_code;
}