rofi  1.6.1
rofi.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>
6  * Copyright © 2013-2020 Qball Cow <qball@gmpclient.org>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  */
28 
30 #define G_LOG_DOMAIN "Rofi"
31 
32 #include <config.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdint.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <locale.h>
41 #include <gmodule.h>
42 #include <xcb/xcb.h>
43 #include <sys/types.h>
44 #include <sysexits.h>
45 
46 #include <glib-unix.h>
47 
48 #include <libgwater-xcb.h>
49 
50 #ifdef USE_NK_GIT_VERSION
51 #include "nkutils-git-version.h"
52 #ifdef NK_GIT_VERSION
53 #define GIT_VERSION NK_GIT_VERSION
54 #endif
55 #endif
56 
57 #include "resources.h"
58 
59 #include "rofi.h"
60 #include "display.h"
61 
62 #include "settings.h"
63 #include "mode.h"
64 #include "helper.h"
65 #include "widgets/textbox.h"
66 #include "xrmoptions.h"
67 #include "dialogs/dialogs.h"
68 
69 #include "view.h"
70 #include "view-internal.h"
71 
72 #include "theme.h"
73 #include "rofi-icon-fetcher.h"
74 
75 #include "timings.h"
76 
77 // Plugin abi version.
78 // TODO: move this check to mode.c
79 #include "mode-private.h"
80 
82 char *pidfile = NULL;
84 const char *cache_dir = NULL;
85 
87 GList *list_of_error_msgs = NULL;
88 
89 static void rofi_collect_modi_destroy ( void );
90 void rofi_add_error_message ( GString *str )
91 {
92  list_of_error_msgs = g_list_append ( list_of_error_msgs, str );
93 }
94 
96 G_MODULE_EXPORT char *config_path = NULL;
98 G_MODULE_EXPORT char *config_path_new = NULL;
100 Mode **modi = NULL;
101 
105 unsigned int num_available_modi = 0;
107 unsigned int num_modi = 0;
109 unsigned int curr_switcher = 0;
110 
112 NkBindings *bindings = NULL;
113 
115 GMainLoop *main_loop = NULL;
116 
118 static int dmenu_mode = FALSE;
120 int return_code = EXIT_SUCCESS;
121 
122 static gboolean old_config_format = FALSE;
123 
124 void process_result ( RofiViewState *state );
125 
126 void rofi_set_return_code ( int code )
127 {
128  return_code = code;
129 }
130 
131 unsigned int rofi_get_num_enabled_modi ( void )
132 {
133  return num_modi;
134 }
135 
136 const Mode * rofi_get_mode ( unsigned int index )
137 {
138  return modi[index];
139 }
140 
148 static int switcher_get ( const char *name )
149 {
150  for ( unsigned int i = 0; i < num_modi; i++ ) {
151  if ( strcmp ( mode_get_name ( modi[i] ), name ) == 0 ) {
152  return i;
153  }
154  }
155  return -1;
156 }
157 
161 static void teardown ( int pfd )
162 {
163  g_debug ( "Teardown" );
164  // Cleanup font setup.
165  textbox_cleanup ( );
166 
168 
169  // Cleanup view
171  // Cleanup pid file.
172  remove_pid_file ( pfd );
173 }
174 static void run_switcher ( ModeMode mode )
175 {
176  // Otherwise check if requested mode is enabled.
177  for ( unsigned int i = 0; i < num_modi; i++ ) {
178  if ( !mode_init ( modi[i] ) ) {
179  GString *str = g_string_new ( "Failed to initialize the mode: " );
180  g_string_append ( str, modi[i]->name );
181  g_string_append ( str, "\n" );
182 
184  g_string_free ( str, FALSE );
185  break;
186  }
187  }
188  // Error dialog must have been created.
189  if ( rofi_view_get_active () != NULL ) {
190  return;
191  }
192  curr_switcher = mode;
194 
195  // User can pre-select a row.
196  if ( find_arg ( "-selected-row" ) >= 0 ) {
197  unsigned int sr = 0;
198  find_arg_uint ( "-selected-row", &( sr ) );
199  rofi_view_set_selected_line ( state, sr );
200  }
201  if ( state ) {
202  rofi_view_set_active ( state );
203  }
204  if ( rofi_view_get_active () == NULL ) {
205  g_main_loop_quit ( main_loop );
206  }
207 }
209 {
210  Mode *sw = state->sw;
211  // rofi_view_set_active ( NULL );
212  if ( sw != NULL ) {
213  unsigned int selected_line = rofi_view_get_selected_line ( state );;
214  MenuReturn mretv = rofi_view_get_return_value ( state );
215  char *input = g_strdup ( rofi_view_get_user_input ( state ) );
216  ModeMode retv = mode_result ( sw, mretv, &input, selected_line );
217  g_free ( input );
218 
219  ModeMode mode = curr_switcher;
220  // Find next enabled
221  if ( retv == NEXT_DIALOG ) {
222  mode = ( mode + 1 ) % num_modi;
223  }
224  else if ( retv == PREVIOUS_DIALOG ) {
225  if ( mode == 0 ) {
226  mode = num_modi - 1;
227  }
228  else {
229  mode = ( mode - 1 ) % num_modi;
230  }
231  }
232  else if ( retv == RELOAD_DIALOG ) {
233  // do nothing.
234  }
235  else if ( retv == RESET_DIALOG ) {
236  rofi_view_clear_input ( state );
237  }
238  else if ( retv < MODE_EXIT ) {
239  mode = ( retv ) % num_modi;
240  }
241  else {
242  mode = retv;
243  }
244  if ( mode != MODE_EXIT ) {
248  rofi_view_switch_mode ( state, modi[mode] );
249  curr_switcher = mode;
250  return;
251  }
252  else {
253  // On exit, free current view, and pop to one above.
254  rofi_view_remove_active ( state );
255  rofi_view_free ( state );
256  return;
257  }
258  }
259 // rofi_view_set_active ( NULL );
260  rofi_view_remove_active ( state );
261  rofi_view_free ( state );
262 }
263 
267 static void print_list_of_modi ( int is_term )
268 {
269  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
270  gboolean active = FALSE;
271  for ( unsigned int j = 0; j < num_modi; j++ ) {
272  if ( modi[j] == available_modi[i] ) {
273  active = TRUE;
274  break;
275  }
276  }
277  printf ( " * %s%s%s%s\n",
278  active ? "+" : "",
279  is_term ? ( active ? color_green : color_red ) : "",
280  available_modi[i]->name,
281  is_term ? color_reset : ""
282  );
283  }
284 }
285 static void print_main_application_options ( int is_term )
286 {
287  print_help_msg ( "-no-config", "", "Do not load configuration, use default values.", NULL, is_term );
288  print_help_msg ( "-v,-version", "", "Print the version number and exit.", NULL, is_term );
289  print_help_msg ( "-dmenu", "", "Start in dmenu mode.", NULL, is_term );
290  print_help_msg ( "-display", "[string]", "X server to contact.", "${DISPLAY}", is_term );
291  print_help_msg ( "-h,-help", "", "This help message.", NULL, is_term );
292  print_help_msg ( "-dump-xresources", "", "Dump the current configuration in Xresources format and exit.", NULL, is_term );
293  print_help_msg ( "-e", "[string]", "Show a dialog displaying the passed message and exit.", NULL, is_term );
294  print_help_msg ( "-markup", "", "Enable pango markup where possible.", NULL, is_term );
295  print_help_msg ( "-normal-window", "", "Behave as a normal window. (experimental)", NULL, is_term );
296  print_help_msg ( "-show", "[mode]", "Show the mode 'mode' and exit. The mode has to be enabled.", NULL, is_term );
297  print_help_msg ( "-no-lazy-grab", "", "Disable lazy grab that, when fail to grab keyboard, does not block but retry later.", NULL, is_term );
298  print_help_msg ( "-no-plugins", "", "Disable loading of external plugins.", NULL, is_term );
299  print_help_msg ( "-plugin-path", "", "Directory used to search for rofi plugins. *DEPRECATED*", NULL, is_term );
300  print_help_msg ( "-dump-config", "", "Dump the current configuration in rasi format and exit.", NULL, is_term );
301  print_help_msg ( "-upgrade-config", "", "Upgrade the old-style configuration file in the new rasi format and exit.", NULL, is_term );
302  print_help_msg ( "-dump-theme", "", "Dump the current theme in rasi format and exit.", NULL, is_term );
303 }
304 static void help ( G_GNUC_UNUSED int argc, char **argv )
305 {
306  int is_term = isatty ( fileno ( stdout ) );
307  printf ( "%s usage:\n", argv[0] );
308  printf ( "\t%s [-options ...]\n\n", argv[0] );
309  printf ( "Command line only options:\n" );
310  print_main_application_options ( is_term );
311  printf ( "DMENU command line options:\n" );
313  printf ( "Global options:\n" );
314  print_options ();
315  printf ( "\n" );
317  printf ( "\n" );
318  printf ( "Detected modi:\n" );
319  print_list_of_modi ( is_term );
320  printf ( "\n" );
321  printf ( "Compile time options:\n" );
322 #ifdef WINDOW_MODE
323  printf ( "\t* window %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
324 #else
325  printf ( "\t* window %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
326 #endif
327 #ifdef ENABLE_DRUN
328  printf ( "\t* drun %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
329 #else
330  printf ( "\t* drun %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
331 #endif
332 #ifdef ENABLE_GCOV
333  printf ( "\t* gcov %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
334 #else
335  printf ( "\t* gcov %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
336 #endif
337 #ifdef ENABLE_ASAN
338  printf ( "\t* asan %senabled%s\n", is_term ? color_green : "", is_term ? color_reset : "" );
339 #else
340  printf ( "\t* asan %sdisabled%s\n", is_term ? color_red : "", is_term ? color_reset : "" );
341 #endif
342  printf ( "\n" );
343  printf ( "For more information see: %sman rofi%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
344 #ifdef GIT_VERSION
345  printf ( " Version: %s"GIT_VERSION "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
346 #else
347  printf ( " Version: %s"VERSION "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
348 #endif
349  printf ( " Bugreports: %s"PACKAGE_BUGREPORT "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
350  printf ( " Support: %s"PACKAGE_URL "%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
351  printf ( " %s#rofi @ freenode.net%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
352  if ( find_arg ( "-no-config" ) < 0 ) {
353  if ( config_path_new ) {
354  printf ( " Configuration file: %s%s%s\n", is_term ? color_bold : "", config_path_new, is_term ? color_reset : "" );
355  }
356  else {
357  printf ( " Configuration file: %s%s%s\n", is_term ? color_bold : "", config_path, is_term ? color_reset : "" );
358  }
359  }
360  else {
361  printf ( " Configuration file: %sDisabled%s\n", is_term ? color_bold : "", is_term ? color_reset : "" );
362  }
363 }
364 
365 static void help_print_disabled_mode ( const char *mode )
366 {
367  int is_term = isatty ( fileno ( stdout ) );
368  // Only output to terminal
369  if ( is_term ) {
370  fprintf ( stderr, "Mode %s%s%s is not enabled. I have enabled it for now.\n",
371  color_red, mode, color_reset );
372  fprintf ( stderr, "Please consider adding %s%s%s to the list of enabled modi: %smodi: %s%s%s,%s%s.\n",
373  color_red, mode, color_reset,
375  color_red, mode, color_reset
376  );
377  }
378 }
379 static void help_print_mode_not_found ( const char *mode )
380 {
381  GString *str = g_string_new ( "" );
382  g_string_printf ( str, "Mode %s is not found.\nThe following modi are known:\n", mode );
383  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
384  gboolean active = FALSE;
385  for ( unsigned int j = 0; j < num_modi; j++ ) {
386  if ( modi[j] == available_modi[i] ) {
387  active = TRUE;
388  break;
389  }
390  }
391  g_string_append_printf ( str, " * %s%s\n",
392  active ? "+" : "",
393  available_modi[i]->name
394  );
395  }
396  rofi_add_error_message ( str );
397 }
398 static void help_print_no_arguments ( void )
399 {
400  int is_term = isatty ( fileno ( stdout ) );
401  // Daemon mode
402  fprintf ( stderr, "Rofi is unsure what to show.\n" );
403  fprintf ( stderr, "Please specify the mode you want to show.\n\n" );
404  fprintf ( stderr, " %srofi%s -show %s{mode}%s\n\n",
405  is_term ? color_bold : "", is_term ? color_reset : "",
406  is_term ? color_green : "", is_term ? color_reset : "" );
407  fprintf ( stderr, "The following modi are enabled:\n" );
408  for ( unsigned int j = 0; j < num_modi; j++ ) {
409  fprintf ( stderr, " * %s%s%s\n",
410  is_term ? color_green : "",
411  modi[j]->name,
412  is_term ? color_reset : "" );
413  }
414  fprintf ( stderr, "\nThe following can be enabled:\n" );
415  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
416  gboolean active = FALSE;
417  for ( unsigned int j = 0; j < num_modi; j++ ) {
418  if ( modi[j] == available_modi[i] ) {
419  active = TRUE;
420  break;
421  }
422  }
423  if ( !active ) {
424  fprintf ( stderr, " * %s%s%s\n",
425  is_term ? color_red : "",
426  available_modi[i]->name,
427  is_term ? color_reset : "" );
428  }
429  }
430  fprintf ( stderr, "\nTo activate a mode, add it to the list of modi in the %smodi%s setting.\n",
431  is_term ? color_green : "", is_term ? color_reset : "" );
432 }
433 
437 static void cleanup ()
438 {
439  for ( unsigned int i = 0; i < num_modi; i++ ) {
440  mode_destroy ( modi[i] );
441  }
443  if ( main_loop != NULL ) {
444  g_main_loop_unref ( main_loop );
445  main_loop = NULL;
446  }
447  // Cleanup
448  display_cleanup ();
449 
450  nk_bindings_free ( bindings );
451 
452  // Cleaning up memory allocated by the Xresources file.
454  g_free ( modi );
455 
456  g_free ( config_path );
457  g_free ( config_path_new );
458 
459  if ( list_of_error_msgs ) {
460  for ( GList *iter = g_list_first ( list_of_error_msgs );
461  iter != NULL; iter = g_list_next ( iter ) ) {
462  g_string_free ( (GString *) iter->data, TRUE );
463  }
464  g_list_free ( list_of_error_msgs );
465  }
466 
467  if ( rofi_theme ) {
469  rofi_theme = NULL;
470  }
471  TIMINGS_STOP ();
474 }
475 
485 Mode * rofi_collect_modi_search ( const char *name )
486 {
487  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
488  if ( g_strcmp0 ( name, available_modi[i]->name ) == 0 ) {
489  return available_modi[i];
490  }
491  }
492  return NULL;
493 }
499 static gboolean rofi_collect_modi_add ( Mode *mode )
500 {
501  Mode *m = rofi_collect_modi_search ( mode->name );
502  if ( m == NULL ) {
503  available_modi = g_realloc ( available_modi, sizeof ( Mode * ) * ( num_available_modi + 1 ) );
504  // Set mode.
507  return TRUE;
508  }
509  return FALSE;
510 }
511 
512 static void rofi_collect_modi_dir ( const char *base_dir )
513 {
514  g_debug ( "Looking into: %s for plugins", base_dir );
515  GDir *dir = g_dir_open ( base_dir, 0, NULL );
516  if ( dir ) {
517  const char *dn = NULL;
518  while ( ( dn = g_dir_read_name ( dir ) ) ) {
519  if ( !g_str_has_suffix ( dn, G_MODULE_SUFFIX ) ) {
520  continue;
521  }
522  char *fn = g_build_filename ( base_dir, dn, NULL );
523  g_debug ( "Trying to open: %s plugin", fn );
524  GModule *mod = g_module_open ( fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL );
525  if ( mod ) {
526  Mode *m = NULL;
527  if ( g_module_symbol ( mod, "mode", (gpointer *) &m ) ) {
528  if ( m->abi_version != ABI_VERSION ) {
529  g_warning ( "ABI version of plugin: '%s' does not match: %08X expecting: %08X", dn, m->abi_version, ABI_VERSION );
530  g_module_close ( mod );
531  }
532  else {
533  m->module = mod;
534  if ( !rofi_collect_modi_add ( m ) ) {
535  g_module_close ( mod );
536  }
537  }
538  }
539  else {
540  g_warning ( "Symbol 'mode' not found in module: %s", dn );
541  g_module_close ( mod );
542  }
543  }
544  else {
545  g_warning ( "Failed to open 'mode' plugin: '%s', error: %s", dn, g_module_error () );
546  }
547  g_free ( fn );
548  }
549  g_dir_close ( dir );
550  }
551 }
552 
556 static void rofi_collect_modi ( void )
557 {
558 #ifdef WINDOW_MODE
559  rofi_collect_modi_add ( &window_mode );
560  rofi_collect_modi_add ( &window_mode_cd );
561 #endif
564 #ifdef ENABLE_DRUN
565  rofi_collect_modi_add ( &drun_mode );
566 #endif
570 
571  if ( find_arg ( "-no-plugins" ) < 0 ) {
572  find_arg_str ( "-plugin-path", &( config.plugin_path ) );
573  g_debug ( "Parse plugin path: %s", config.plugin_path );
575  /* ROFI_PLUGIN_PATH */
576  const char *path = g_getenv ( "ROFI_PLUGIN_PATH" );
577  if ( path != NULL ) {
578  gchar ** paths = g_strsplit ( path, ":", -1 );
579  for ( unsigned int i = 0; paths[i]; i++ ) {
580  rofi_collect_modi_dir ( paths[i] );
581  }
582  g_strfreev ( paths );
583  }
584  }
585 }
586 
590 static void rofi_collect_modi_setup ( void )
591 {
592  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
594  }
595 }
596 static void rofi_collect_modi_destroy ( void )
597 {
598  for ( unsigned int i = 0; i < num_available_modi; i++ ) {
599  if ( available_modi[i]->module ) {
600  GModule *mod = available_modi[i]->module;
601  available_modi[i] = NULL;
602  g_module_close ( mod );
603  }
604  if ( available_modi[i] ) {
605  mode_free ( &( available_modi[i] ) );
606  }
607  }
608  g_free ( available_modi );
609  available_modi = NULL;
610  num_available_modi = 0;
611 }
612 
620 static int add_mode ( const char * token )
621 {
622  unsigned int index = num_modi;
623  // Resize and add entry.
624  modi = (Mode * *) g_realloc ( modi, sizeof ( Mode* ) * ( num_modi + 1 ) );
625 
626  Mode *mode = rofi_collect_modi_search ( token );
627  if ( mode ) {
628  modi[num_modi] = mode;
629  num_modi++;
630  }
631  else if ( script_switcher_is_valid ( token ) ) {
632  // If not build in, use custom modi.
633  Mode *sw = script_switcher_parse_setup ( token );
634  if ( sw != NULL ) {
635  // Add to available list, so combi can find it.
636  rofi_collect_modi_add ( sw );
637  modi[num_modi] = sw;
638  num_modi++;
639  }
640  }
641  return ( index == num_modi ) ? -1 : (int) index;
642 }
643 static gboolean setup_modi ( void )
644 {
645  const char *const sep = ",#";
646  char *savept = NULL;
647  // Make a copy, as strtok will modify it.
648  char *switcher_str = g_strdup ( config.modi );
649  // Split token on ','. This modifies switcher_str.
650  for ( char *token = strtok_r ( switcher_str, sep, &savept ); token != NULL; token = strtok_r ( NULL, sep, &savept ) ) {
651  if ( add_mode ( token ) == -1 ) {
652  help_print_mode_not_found ( token );
653  }
654  }
655  // Free string that was modified by strtok_r
656  g_free ( switcher_str );
657  return FALSE;
658 }
659 
664 void rofi_quit_main_loop ( void )
665 {
666  g_main_loop_quit ( main_loop );
667 }
668 
669 static gboolean main_loop_signal_handler_int ( G_GNUC_UNUSED gpointer data )
670 {
671  // Break out of loop.
672  g_main_loop_quit ( main_loop );
673  return G_SOURCE_CONTINUE;
674 }
675 static void show_error_dialog ()
676 {
677  GString *emesg = g_string_new ( "The following errors were detected when starting rofi:\n" );
678  GList *iter = g_list_first ( list_of_error_msgs );
679  int index = 0;
680  for (; iter != NULL && index < 2; iter = g_list_next ( iter ) ) {
681  GString *msg = (GString *) ( iter->data );
682  g_string_append ( emesg, "\n\n" );
683  g_string_append ( emesg, msg->str );
684  index++;
685  }
686  if ( g_list_length ( iter ) > 1 ) {
687  g_string_append_printf ( emesg, "\nThere are <b>%d</b> more errors.", g_list_length ( iter ) - 1 );
688  }
690  g_string_free ( emesg, TRUE );
691  rofi_set_return_code ( EX_DATAERR );
692 }
693 
694 static gboolean startup ( G_GNUC_UNUSED gpointer data )
695 {
696  TICK_N ( "Startup" );
697  // flags to run immediately and exit
698  char *sname = NULL;
699  char *msg = NULL;
700  MenuFlags window_flags = MENU_NORMAL;
701 
702  if ( find_arg ( "-normal-window" ) >= 0 ) {
703  window_flags |= MENU_NORMAL_WINDOW;
704  }
705  TICK_N ( "Grab keyboard" );
706  __create_window ( window_flags );
707  TICK_N ( "Create Window" );
708  // Parse the keybindings.
709  TICK_N ( "Parse ABE" );
710  // Sanity check
712  TICK_N ( "Config sanity check" );
713 
714  if ( list_of_error_msgs != NULL ) {
716  return G_SOURCE_REMOVE;
717  }
718  // Dmenu mode.
719  if ( dmenu_mode == TRUE ) {
720  // force off sidebar mode:
721  config.sidebar_mode = FALSE;
722  int retv = dmenu_switcher_dialog ();
723  if ( retv ) {
724  rofi_set_return_code ( EXIT_SUCCESS );
725  // Directly exit.
726  g_main_loop_quit ( main_loop );
727  }
728  }
729  else if ( find_arg_str ( "-e", &( msg ) ) ) {
730  int markup = FALSE;
731  if ( find_arg ( "-markup" ) >= 0 ) {
732  markup = TRUE;
733  }
734  if ( !rofi_view_error_dialog ( msg, markup ) ) {
735  g_main_loop_quit ( main_loop );
736  }
737  }
738  else if ( find_arg_str ( "-show", &sname ) == TRUE ) {
739  int index = switcher_get ( sname );
740  if ( index < 0 ) {
741  // Add it to the list
742  index = add_mode ( sname );
743  // Complain
744  if ( index >= 0 ) {
745  help_print_disabled_mode ( sname );
746  }
747  // Run it anyway if found.
748  }
749  if ( index >= 0 ) {
750  run_switcher ( index );
751  }
752  else {
753  help_print_mode_not_found ( sname );
755  return G_SOURCE_REMOVE;
756  }
757  }
758  else if ( find_arg ( "-show" ) >= 0 && num_modi > 0 ) {
759  run_switcher ( 0 );
760  }
761  else{
763 
764  g_main_loop_quit ( main_loop );
765  }
766 
767  return G_SOURCE_REMOVE;
768 }
769 
770 static gboolean record ( G_GNUC_UNUSED void *data )
771 {
773  return G_SOURCE_CONTINUE;
774 }
783 int main ( int argc, char *argv[] )
784 {
785  TIMINGS_START ();
786 
787  cmd_set_arguments ( argc, argv );
788 
789  // Version
790  if ( find_arg ( "-v" ) >= 0 || find_arg ( "-version" ) >= 0 ) {
791 #ifdef GIT_VERSION
792  g_print ( "Version: "GIT_VERSION "\n" );
793 #else
794  g_print ( "Version: "VERSION "\n" );
795 #endif
796  return EXIT_SUCCESS;
797  }
798 
799  {
800  const char *ro_pid = g_getenv ( "ROFI_OUTSIDE" );
801  if ( ro_pid != NULL ) {
802  int ro_pidi = g_ascii_strtoll ( ro_pid, NULL, 0 );
803  if ( kill ( ro_pidi, 0 ) == 0 ) {
804  printf ( "Do not launch rofi from inside rofi.\r\n" );
805  return EXIT_FAILURE;
806  }
807  }
808  }
809 
810  // Detect if we are in dmenu mode.
811  // This has two possible causes.
812  // 1 the user specifies it on the command-line.
813  if ( find_arg ( "-dmenu" ) >= 0 ) {
814  dmenu_mode = TRUE;
815  }
816  // 2 the binary that executed is called dmenu (e.g. symlink to rofi)
817  else{
818  // Get the base name of the executable called.
819  char *base_name = g_path_get_basename ( argv[0] );
820  const char * const dmenu_str = "dmenu";
821  dmenu_mode = ( strcmp ( base_name, dmenu_str ) == 0 );
822  // Free the basename for dmenu detection.
823  g_free ( base_name );
824  }
825  TICK ();
826 
827  // Create pid file path.
828  const char *path = g_get_user_runtime_dir ();
829  if ( path ) {
830  if ( g_mkdir_with_parents ( path, 0700 ) < 0 ) {
831  g_warning ( "Failed to create user runtime directory: %s with error: %s", path, g_strerror ( errno ) );
832  pidfile = g_build_filename ( g_get_home_dir (), ".rofi.pid", NULL );
833  }
834  else {
835  pidfile = g_build_filename ( path, "rofi.pid", NULL );
836  }
837  }
838  config_parser_add_option ( xrm_String, "pid", (void * *) &pidfile, "Pidfile location" );
839 
840  if ( find_arg ( "-config" ) < 0 ) {
841  const char *cpath = g_get_user_config_dir ();
842  if ( cpath ) {
843  config_path = g_build_filename ( cpath, "rofi", "config", NULL );
844  config_path_new = g_strconcat ( config_path, ".rasi", NULL );
845  }
846  }
847  else {
848  char *c = NULL;
849  find_arg_str ( "-config", &c );
850  if ( g_str_has_suffix ( c, ".rasi" ) ) {
852  }
853  else {
855  }
856  }
857 
858  TICK ();
859  if ( setlocale ( LC_ALL, "" ) == NULL ) {
860  g_warning ( "Failed to set locale." );
861  cleanup ();
862  return EXIT_FAILURE;
863  }
864 
865  TICK_N ( "Setup Locale" );
867  TICK_N ( "Collect MODI" );
869  TICK_N ( "Setup MODI" );
870 
871  main_loop = g_main_loop_new ( NULL, FALSE );
872 
873  TICK_N ( "Setup mainloop" );
874 
875  bindings = nk_bindings_new ( 0 );
876  TICK_N ( "NK Bindings" );
877 
878  if ( !display_setup ( main_loop, bindings ) ) {
879  g_warning ( "Connection has error" );
880  cleanup ();
881  return EXIT_FAILURE;
882  }
883  TICK_N ( "Setup Display" );
884 
885  // Setup keybinding
886  setup_abe ();
887  TICK_N ( "Setup abe" );
888 
889  if ( find_arg ( "-no-config" ) < 0 ) {
890  // Load distro default settings
891  gboolean found_system = FALSE;
892  const char * const * dirs = g_get_system_config_dirs ();
893  if ( dirs ) {
894  for ( unsigned int i = 0; !found_system && dirs[i]; i++ ) {
896  gchar *etc = g_build_filename ( dirs[i], "rofi.rasi", NULL );
897  g_debug ( "Look for default config file: %s", etc );
898  if ( g_file_test ( etc, G_FILE_TEST_IS_REGULAR ) ) {
899  g_debug ( "Parsing: %s", etc );
900  rofi_theme_parse_file ( etc );
901  found_system = TRUE;
902  }
903  else {
905  gchar *xetc = g_build_filename ( dirs[i], "rofi.conf", NULL );
906  g_debug ( "Look for default config file: %s", xetc );
907  if ( g_file_test ( xetc, G_FILE_TEST_IS_REGULAR ) ) {
909  old_config_format = TRUE;
910  found_system = TRUE;
911  }
912  g_free ( xetc );
913  }
914  g_free ( etc );
915  }
916  }
917  if ( !found_system ) {
919  gchar *etc = g_build_filename ( SYSCONFDIR, "rofi.rasi", NULL );
920  g_debug ( "Look for default config file: %s", etc );
921  if ( g_file_test ( etc, G_FILE_TEST_IS_REGULAR ) ) {
922  g_debug ( "Look for default config file: %s", etc );
923  rofi_theme_parse_file ( etc );
924  }
925  else {
927  gchar *xetc = g_build_filename ( SYSCONFDIR, "rofi.conf", NULL );
928  g_debug ( "Look for default config file: %s", xetc );
929  if ( g_file_test ( xetc, G_FILE_TEST_IS_REGULAR ) ) {
931  old_config_format = TRUE;
932  }
933  g_free ( xetc );
934  }
935  g_free ( etc );
936  }
937  // Load in config from X resources.
939 
940  if ( config_path_new && g_file_test ( config_path_new, G_FILE_TEST_IS_REGULAR ) ) {
943  rofi_theme = NULL;
944  }
945  }
946  else {
947  g_free ( config_path_new );
948  config_path_new = NULL;
949  if ( g_file_test ( config_path, G_FILE_TEST_IS_REGULAR ) ) {
951  old_config_format = TRUE;
952  }
953  }
954  }
955  find_arg_str ( "-theme", &( config.theme ) );
956  if ( config.theme ) {
957  TICK_N ( "Parse theme" );
958  if ( rofi_theme_parse_file ( config.theme ) ) {
959  // TODO: instantiate fallback theme.?
961  rofi_theme = NULL;
962  }
963  TICK_N ( "Parsed theme" );
964  }
965  // Parse command line for settings, independent of other -no-config.
967  TICK_N ( "Load cmd config " );
968 
969  if ( old_config_format ) {
970  g_warning ( "The old Xresources based configuration format is deprecated." );
971  g_warning ( "Please upgrade: rofi -upgrade-config." );
972  }
974 
975  // Get the path to the cache dir.
976  cache_dir = g_get_user_cache_dir ();
977 
978  if ( config.cache_dir != NULL ) {
980  }
981 
982  if ( g_mkdir_with_parents ( cache_dir, 0700 ) < 0 ) {
983  g_warning ( "Failed to create cache directory: %s", g_strerror ( errno ) );
984  return EXIT_FAILURE;
985  }
986 
988  char *windowid = NULL;
989  if ( !dmenu_mode ) {
990  // setup_modi
991  if ( setup_modi () ) {
992  cleanup ();
993  return EXIT_FAILURE;
994  }
995  TICK_N ( "Setup Modi" );
996  }
997  else {
998  // Hack for dmenu compatibility.
999  if ( find_arg_str ( "-w", &windowid ) == TRUE ) {
1000  config.monitor = g_strdup_printf ( "wid:%s", windowid );
1001  windowid = config.monitor;
1002  }
1003  }
1004  if ( rofi_theme_is_empty ( ) ) {
1005  GBytes *theme_data = g_resource_lookup_data (
1006  resources_get_resource (),
1007  "/org/qtools/rofi/default_theme.rasi",
1008  G_RESOURCE_LOOKUP_FLAGS_NONE,
1009  NULL );
1010  if ( theme_data ) {
1011  const char *theme = g_bytes_get_data ( theme_data, NULL );
1012  if ( rofi_theme_parse_string ( (const char *) theme ) ) {
1013  g_warning ( "Failed to parse default theme. Giving up.." );
1014  if ( list_of_error_msgs ) {
1015  for ( GList *iter = g_list_first ( list_of_error_msgs );
1016  iter != NULL; iter = g_list_next ( iter ) ) {
1017  g_warning ( "Error: %s%s%s",
1018  color_bold, ( (GString *) iter->data )->str, color_reset );
1019  }
1020  }
1021  rofi_theme = NULL;
1022  cleanup ();
1023  return EXIT_FAILURE;
1024  }
1025  g_bytes_unref ( theme_data );
1026  }
1027  rofi_theme_convert_old ();
1028  }
1029 
1033  const char ** theme_str = find_arg_strv ( "-theme-str" );
1034  if ( theme_str ) {
1035  for ( int index = 0; theme_str && theme_str[index]; index++ ) {
1036  if ( rofi_theme_parse_string ( theme_str[index] ) ) {
1038  rofi_theme = NULL;
1039  }
1040  }
1041  g_free ( theme_str );
1042  }
1043 
1044  if ( find_arg ( "-dump-theme" ) >= 0 ) {
1046  cleanup ();
1047  return EXIT_SUCCESS;
1048  }
1049  if ( find_arg ( "-upgrade-config" ) >= 0 ) {
1050  setup_modi ();
1051 
1052  for ( unsigned int i = 0; i < num_modi; i++ ) {
1053  mode_init ( modi[i] );
1054  }
1055 
1056  const char *cpath = g_get_user_config_dir ();
1057  if ( cpath ) {
1058  char *fcpath = g_build_filename ( cpath, "rofi", NULL );
1059  if ( !g_file_test ( fcpath, G_FILE_TEST_IS_DIR ) && g_mkdir_with_parents ( fcpath, 0700 ) < 0 ) {
1060  g_warning ( "Failed to create rofi configuration directory: %s", fcpath );
1061  cleanup ();
1062  g_free ( fcpath );
1063  return EXIT_FAILURE;
1064  }
1065  g_free ( fcpath );
1066  fcpath = g_build_filename ( cpath, "rofi", "config.rasi", NULL );
1067  if ( g_file_test ( fcpath, G_FILE_TEST_IS_REGULAR ) ) {
1068  g_warning ( "New configuration file already exists: %s", fcpath );
1069  cleanup ();
1070  g_free ( fcpath );
1071  return EXIT_FAILURE;
1072  }
1073  FILE *fd = fopen ( fcpath, "w" );
1074  if ( fd == NULL ) {
1075  g_warning ( "Failed to open new rofi configuration file: %s: %s", fcpath, strerror ( errno ) );
1076  cleanup ();
1077  g_free ( fcpath );
1078  return EXIT_FAILURE;
1079  }
1081  fprintf ( stdout, "\n***** Generated configuration file in: %s *****\n", fcpath );
1082 
1083  fflush ( fd );
1084  fclose ( fd );
1085  g_free ( fcpath );
1086  }
1087  else {
1088  g_warning ( "Failed to get user configuration directory." );
1089  cleanup ();
1090  return EXIT_FAILURE;
1091  }
1092  cleanup ();
1093  return EXIT_SUCCESS;
1094  }
1095  if ( find_arg ( "-dump-config" ) >= 0 ) {
1096  config_parse_dump_config_rasi_format ( stdout, FALSE );
1097  cleanup ();
1098  return EXIT_SUCCESS;
1099  }
1100  // Dump.
1101  // catch help request
1102  if ( find_arg ( "-h" ) >= 0 || find_arg ( "-help" ) >= 0 || find_arg ( "--help" ) >= 0 ) {
1103  help ( argc, argv );
1104  cleanup ();
1105  return EXIT_SUCCESS;
1106  }
1107  if ( find_arg ( "-dump-xresources" ) >= 0 ) {
1109  cleanup ();
1110  return EXIT_SUCCESS;
1111  }
1112 
1113  unsigned int interval = 1;
1114  if ( find_arg_uint ( "-record-screenshots", &interval ) ) {
1115  g_timeout_add ( 1000 / (double) interval, record, NULL );
1116  }
1117  if ( find_arg ( "-benchmark-ui" ) >= 0 ) {
1118  config.benchmark_ui = TRUE;
1119  }
1120 
1122  TICK_N ( "Workers initialize" );
1124  TICK_N ( "Icon fetcher initialize" );
1125 
1126  // Create pid file
1127  int pfd = create_pid_file ( pidfile );
1128  TICK_N ( "Pid file created" );
1129  if ( pfd < 0 ) {
1130  cleanup ();
1131  return EXIT_FAILURE;
1132  }
1133  textbox_setup ();
1134  TICK_N ( "Text box setup" );
1135 
1136  if ( !display_late_setup () ) {
1137  g_warning ( "Failed to properly finish display setup" );
1138  cleanup ();
1139  return EXIT_FAILURE;
1140  }
1141  TICK_N ( "Setup late Display" );
1142 
1144  TICK_N ( "Theme setup" );
1145 
1146  // Setup signal handling sources.
1147  // SIGINT
1148  g_unix_signal_add ( SIGINT, main_loop_signal_handler_int, NULL );
1149 
1150  g_idle_add ( startup, NULL );
1151 
1152  // Start mainloop.
1153  g_main_loop_run ( main_loop );
1154  teardown ( pfd );
1155  cleanup ();
1156 
1157  /* dirty hack */
1158  g_free ( windowid );
1159  return return_code;
1160 }
Mode combi_mode
Definition: combi.c:302
void config_parse_cmd_options(void)
Definition: xrmoptions.c:415
void config_parse_xresource_options_file(const char *filename)
Definition: xrmoptions.c:347
void print_options(void)
Definition: xrmoptions.c:757
void config_parser_add_option(XrmOptionType type, const char *key, void **value, const char *comment)
Definition: xrmoptions.c:243
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
Definition: xrmoptions.c:775
void config_parse_dump_config_rasi_format(FILE *out, gboolean changes)
Dump configuration in rasi format.
Definition: xrmoptions.c:638
@ xrm_String
Definition: xrmoptions.h:72
void config_xresource_free(void)
Definition: xrmoptions.c:518
void config_parse_xresource_dump(void)
Definition: xrmoptions.c:576
void config_parse_xresource_options(xcb_stuff *xcb)
Definition: xrmoptions.c:338
int dmenu_switcher_dialog(void)
Definition: dmenu.c:659
void print_dmenu_options(void)
Definition: dmenu.c:755
Mode file_browser_mode
Definition: filebrowser.c:463
void cmd_set_arguments(int argc, char **argv)
Definition: helper.c:75
int create_pid_file(const char *pidfile)
Definition: helper.c:533
const char ** find_arg_strv(const char *const key)
Definition: helper.c:320
void remove_pid_file(int fd)
Definition: helper.c:572
char * rofi_expand_path(const char *input)
Definition: helper.c:711
int find_arg_str(const char *const key, char **val)
Definition: helper.c:309
int find_arg_uint(const char *const key, unsigned int *val)
Definition: helper.c:351
int find_arg(const char *const key)
Definition: helper.c:299
int config_sanity_check(void)
Definition: helper.c:599
Mode help_keys_mode
Definition: help-keys.c:111
void rofi_icon_fetcher_destroy(void)
void rofi_icon_fetcher_init(void)
gboolean parse_keys_abe(NkBindings *bindings)
Definition: keyb.c:148
void setup_abe(void)
Definition: keyb.c:134
void mode_destroy(Mode *mode)
Definition: mode.c:49
int mode_init(Mode *mode)
Definition: mode.c:42
void mode_free(Mode **mode)
Definition: mode.c:129
ModeMode mode_result(Mode *mode, int menu_retv, char **input, unsigned int selected_line)
Definition: mode.c:97
MenuReturn
Definition: mode.h:67
ModeMode
Definition: mode.h:50
const char * mode_get_name(const Mode *mode)
Definition: mode.c:123
void mode_set_config(Mode *mode)
Definition: mode.c:162
@ MODE_EXIT
Definition: mode.h:52
@ NEXT_DIALOG
Definition: mode.h:54
@ RELOAD_DIALOG
Definition: mode.h:56
@ PREVIOUS_DIALOG
Definition: mode.h:58
@ RESET_DIALOG
Definition: mode.h:60
void rofi_quit_main_loop(void)
Definition: rofi.c:664
#define color_reset
Definition: rofi.h:90
#define color_bold
Definition: rofi.h:92
Mode * rofi_collect_modi_search(const char *name)
Definition: rofi.c:485
#define color_red
Definition: rofi.h:98
#define ERROR_MSG_MARKUP
Definition: rofi.h:110
void rofi_set_return_code(int code)
Definition: rofi.c:126
unsigned int rofi_get_num_enabled_modi(void)
Definition: rofi.c:131
const Mode * rofi_get_mode(unsigned int index)
Definition: rofi.c:136
const char * cache_dir
Definition: rofi.c:84
void rofi_add_error_message(GString *str)
Definition: rofi.c:90
#define color_green
Definition: rofi.h:96
Mode run_mode
Definition: run.c:411
Mode * script_switcher_parse_setup(const char *str)
Definition: script.c:422
gboolean script_switcher_is_valid(const char *token)
Definition: script.c:459
Mode ssh_mode
Definition: ssh.c:646
#define TICK()
Definition: timings.h:64
#define TIMINGS_START()
Definition: timings.h:60
#define TIMINGS_STOP()
Definition: timings.h:73
#define TICK_N(a)
Definition: timings.h:69
void textbox_cleanup(void)
Definition: textbox.c:841
void textbox_setup(void)
Definition: textbox.c:815
void rofi_view_cleanup()
Definition: view.c:1949
void __create_window(MenuFlags menu_flags)
Definition: view.c:731
void rofi_view_clear_input(RofiViewState *state)
Definition: view.c:2041
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition: view.c:2054
void rofi_view_remove_active(RofiViewState *state)
Definition: view.c:496
RofiViewState * rofi_view_get_active(void)
Definition: view.c:491
int rofi_view_error_dialog(const char *msg, int markup)
Definition: view.c:1898
void rofi_view_set_active(RofiViewState *state)
Definition: view.c:505
MenuFlags
Definition: view.h:44
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition: view.c:563
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition: view.c:528
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition: view.c:1821
void rofi_view_free(RofiViewState *state)
Definition: view.c:544
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition: view.c:588
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition: view.c:568
@ MENU_NORMAL_WINDOW
Definition: view.h:50
@ MENU_NORMAL
Definition: view.h:46
#define ABI_VERSION
Definition: mode-private.h:34
static void help(G_GNUC_UNUSED int argc, char **argv)
Definition: rofi.c:304
static void rofi_collect_modi_setup(void)
Definition: rofi.c:590
static void rofi_collect_modi_destroy(void)
Definition: rofi.c:596
int main(int argc, char *argv[])
Definition: rofi.c:783
static int switcher_get(const char *name)
Definition: rofi.c:148
static gboolean record(G_GNUC_UNUSED void *data)
Definition: rofi.c:770
GList * list_of_error_msgs
Definition: rofi.c:87
unsigned int num_modi
Definition: rofi.c:107
G_MODULE_EXPORT char * config_path
Definition: rofi.c:96
NkBindings * bindings
Definition: rofi.c:112
Mode ** available_modi
Definition: rofi.c:103
static void print_main_application_options(int is_term)
Definition: rofi.c:285
static void run_switcher(ModeMode mode)
Definition: rofi.c:174
static gboolean old_config_format
Definition: rofi.c:122
static void cleanup()
Definition: rofi.c:437
static void help_print_mode_not_found(const char *mode)
Definition: rofi.c:379
static void print_list_of_modi(int is_term)
Definition: rofi.c:267
static void rofi_collect_modi_dir(const char *base_dir)
Definition: rofi.c:512
static gboolean startup(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:694
static void rofi_collect_modi(void)
Definition: rofi.c:556
GMainLoop * main_loop
Definition: rofi.c:115
static void teardown(int pfd)
Definition: rofi.c:161
char * pidfile
Definition: rofi.c:82
int return_code
Definition: rofi.c:120
static void show_error_dialog()
Definition: rofi.c:675
void process_result(RofiViewState *state)
Definition: rofi.c:208
unsigned int num_available_modi
Definition: rofi.c:105
static int add_mode(const char *token)
Definition: rofi.c:620
static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:669
static gboolean setup_modi(void)
Definition: rofi.c:643
unsigned int curr_switcher
Definition: rofi.c:109
Mode ** modi
Definition: rofi.c:100
static void help_print_no_arguments(void)
Definition: rofi.c:398
static int dmenu_mode
Definition: rofi.c:118
static void help_print_disabled_mode(const char *mode)
Definition: rofi.c:365
static gboolean rofi_collect_modi_add(Mode *mode)
Definition: rofi.c:499
G_MODULE_EXPORT char * config_path_new
Definition: rofi.c:98
Settings config
char * cache_dir
Definition: settings.h:195
char * theme
Definition: settings.h:184
char * plugin_path
Definition: settings.h:186
char * filter
Definition: settings.h:161
char * modi
Definition: settings.h:62
unsigned int sidebar_mode
Definition: settings.h:141
gboolean benchmark_ui
Definition: settings.h:205
char * monitor
Definition: settings.h:156
unsigned int abi_version
Definition: mode-private.h:154
GModule * module
Definition: mode-private.h:197
char * name
Definition: mode-private.h:156
void rofi_theme_parse_process_conditionals(void)
Definition: theme.c:1346
void rofi_theme_print(ThemeWidget *widget)
Definition: theme.c:536
void rofi_theme_free(ThemeWidget *widget)
Definition: theme.c:246
gboolean rofi_theme_is_empty(void)
Definition: theme.c:1042
gboolean rofi_theme_parse_string(const char *string)
ThemeWidget * rofi_theme
gboolean rofi_theme_parse_file(const char *file)
void rofi_capture_screenshot(void)
Definition: view.c:177
void rofi_view_workers_initialize(void)
Definition: view.c:1987
void rofi_view_workers_finalize(void)
Definition: view.c:2014
gboolean display_late_setup(void)
Definition: xcb.c:1358
void display_early_cleanup(void)
Definition: xcb.c:1396
void display_cleanup(void)
Definition: xcb.c:1403
xcb_stuff * xcb
Definition: xcb.c:86
gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings)
Definition: xcb.c:1163
void display_dump_monitor_layout(void)
Definition: xcb.c:495