diff --git a/config/config.c b/config/config.c index ecb1e2fe..593a36c5 100644 --- a/config/config.c +++ b/config/config.c @@ -116,6 +116,9 @@ Settings config = { .matching_method = MM_NORMAL, /** Desktop entry fields to match*/ .drun_match_fields = "name,generic,exec,categories", + /** Desktop entry show actions */ + .drun_show_actions = FALSE, + /** Desktop entry show actions */ /** Window fields to match in window mode*/ .window_match_fields = "all", /** Monitor */ diff --git a/doc/rofi-theme-selector.1 b/doc/rofi-theme-selector.1 index 47d0bff7..6a9630c7 100644 --- a/doc/rofi-theme-selector.1 +++ b/doc/rofi-theme-selector.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "ROFI\-THEME\-SELECTOR" "1" "January 2018" "" "" +.TH "ROFI\-THEME\-SELECTOR" "1" "May 2018" "" "" . .SH "NAME" \fBrofi\-theme\-selector\fR \- Preview and apply themes for \fBrofi\fR diff --git a/doc/rofi-theme.5 b/doc/rofi-theme.5 index 15a2750c..23ba0f54 100644 --- a/doc/rofi-theme.5 +++ b/doc/rofi-theme.5 @@ -7,12 +7,12 @@ \fBrofi\-theme\fR \- Rofi theme format files . .SH "DESCRIPTION" -The need for a new theme format was motivated by the fact that the way rofi handled widgets has changed\. From a very static drawing of lines and text to a nice structured form of packing widgets\. This change made it possible to provide a more flexible theme framework\. The old theme format and config file are not flexible enough to expose these options in a user\-friendly way\. Therefore, a new file format has been created, replacing the old one\. +The need for a new theme format was motivated by the fact that the way rofi handled widgets has changed\. From a very static drawing of lines and text to a nice structured form of packing widgets\. This change made it possible to provide a more flexible theme framework\. The old theme format and config file are not flexible enough to expose these options in a user\-friendly way\. Therefor, a new file format has been created, replacing the old one\. . .SH "FORMAT SPECIFICATION" . .SH "Encoding" -The encoding of the file is utf\-8\. Both unix (\fB\en\fR) and windows (\fB\er\en\fR) newline formats are supported, though unix is preferred\. +The encoding of the file is utf\-8\. Both unix (\fB\en\fR) and windows (\fB\er\en\fR) newlines format are supported\. But unix is preferred\. . .SH "Comments" C and C++ file comments are supported\. @@ -121,7 +121,7 @@ It is advised to define the \fIglobal properties section\fR on top of the file t If there are multiple sections with the same name, they are merged\. Duplicate properties are overwritten and the last parsed entry kept\. . .SH "Global properties section" -A theme can have one or more global properties sections\. If there are more than one, they will be merged\. +A theme can have one or more global properties sections\. If there is more than one, they will be merged\. . .P The global properties section denotes the defaults for each element\. Each property of this section can be referenced with \fB@{identifier}\fR (See Properties section) diff --git a/doc/rofi.1 b/doc/rofi.1 index d422355b..daeadd0a 100644 --- a/doc/rofi.1 +++ b/doc/rofi.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "ROFI" "1" "June 2018" "" "" +.TH "ROFI" "1" "July 2018" "" "" . .SH "NAME" \fBrofi\fR \- A window switcher, application launcher, ssh dialog and dmenu replacement @@ -414,6 +414,22 @@ Default: \fIname,generic,exec,categories\fR .IP "" 0 . .P +\fB\-[no\-]drun\-show\-actions\fR +. +.P +Show actions present in the Desktop files\. +. +.IP "" 4 +. +.nf + +Default: false +. +.fi +. +.IP "" 0 +. +.P \fB\-window\-match\-fields\fR \fIfield1\fR,\fIfield2\fR,\.\.\. . .P diff --git a/doc/rofi.1.markdown b/doc/rofi.1.markdown index a3ae4877..db33ac34 100644 --- a/doc/rofi.1.markdown +++ b/doc/rofi.1.markdown @@ -239,6 +239,12 @@ The different fields are: Default: *name,generic,exec,categories* +`-[no-]drun-show-actions` + +Show actions present in the Desktop files. + + Default: false + `-window-match-fields` *field1*,*field2*,... When using window mode, match only with the specified fields. diff --git a/doc/test_xr.txt b/doc/test_xr.txt index fe2ea9aa..a2578524 100644 --- a/doc/test_xr.txt +++ b/doc/test_xr.txt @@ -42,6 +42,8 @@ rofi.window-command: xkill -id {window} ! rofi.icon-theme: ! "Desktop entry fields to match in drun" Set from: Default ! rofi.drun-match-fields: name,generic,exec,categories +! "Desktop entry show actions." Set from: Default +! rofi.drun-show-actions: false ! "Disable history in run/ssh" Set from: File rofi.disable-history: false ! "Use sorting" Set from: Default diff --git a/include/settings.h b/include/settings.h index cfd1aaf6..40aaf04c 100644 --- a/include/settings.h +++ b/include/settings.h @@ -116,6 +116,8 @@ typedef struct char * sorting_method; /** Desktop entries to match in drun */ char * drun_match_fields; + /** Desktop entry show actions */ + unsigned int drun_show_actions; /** Search case sensitivity */ unsigned int case_sensitive; /** Cycle through in the element list */ diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c index fa71d7e1..cecba726 100644 --- a/source/dialogs/drun.c +++ b/source/dialogs/drun.c @@ -57,7 +57,7 @@ #define DRUN_CACHE_FILE "rofi3.druncache" -#define DRUN_GROUP_NAME "Desktop Entry" +char *DRUN_GROUP_NAME = "Desktop Entry"; typedef struct _DRunModePrivateData DRunModePrivateData; @@ -69,6 +69,8 @@ typedef struct { thread_state st; DRunModePrivateData *pd; + /* category */ + char *action; /* Root */ char *root; /* Path to desktop file */ @@ -226,7 +228,7 @@ static void exec_cmd_entry ( DRunModeEntry *e ) } const gchar *fp = g_strstrip ( str ); - gchar *exec_path = g_key_file_get_string ( e->key_file, DRUN_GROUP_NAME, "Path", NULL ); + gchar *exec_path = g_key_file_get_string ( e->key_file, e->action, "Path", NULL ); if ( exec_path != NULL && strlen ( exec_path ) == 0 ) { // If it is empty, ignore this property. (#529) g_free ( exec_path ); @@ -238,14 +240,14 @@ static void exec_cmd_entry ( DRunModeEntry *e ) .icon = e->icon_name, .app_id = e->app_id, }; - gboolean sn = g_key_file_get_boolean ( e->key_file, DRUN_GROUP_NAME, "StartupNotify", NULL ); + gboolean sn = g_key_file_get_boolean ( e->key_file, e->action, "StartupNotify", NULL ); gchar *wmclass = NULL; - if ( sn && g_key_file_has_key ( e->key_file, DRUN_GROUP_NAME, "StartupWMClass", NULL ) ) { - context.wmclass = wmclass = g_key_file_get_string ( e->key_file, DRUN_GROUP_NAME, "StartupWMClass", NULL ); + if ( sn && g_key_file_has_key ( e->key_file, e->action, "StartupWMClass", NULL ) ) { + context.wmclass = wmclass = g_key_file_get_string ( e->key_file, e->action, "StartupWMClass", NULL ); } // Returns false if not found, if key not found, we don't want run in terminal. - gboolean terminal = g_key_file_get_boolean ( e->key_file, DRUN_GROUP_NAME, "Terminal", NULL ); + gboolean terminal = g_key_file_get_boolean ( e->key_file, e->action, "Terminal", NULL ); if ( helper_execute_command ( exec_path, fp, terminal, sn ? &context : NULL ) ) { char *path = g_build_filename ( cache_dir, DRUN_CACHE_FILE, NULL ); // Store it based on the unique identifiers (desktop_id). @@ -259,8 +261,9 @@ static void exec_cmd_entry ( DRunModeEntry *e ) /** * This function absorbs/freeÅ› path, so this is no longer available afterwards. */ -static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, const char *path, const gchar *basename ) +static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, const char *path, const gchar *basename, char *action ) { + int parse_action = ( config.drun_show_actions && action != DRUN_GROUP_NAME ); // Create ID on stack. // We know strlen (path ) > strlen(root)+1 const ssize_t id_len = strlen ( path ) - strlen ( root ); @@ -273,7 +276,7 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c } // Check if item is on disabled list. - if ( g_hash_table_contains ( pd->disabled_entries, id ) ) { + if ( g_hash_table_contains ( pd->disabled_entries, id ) && !parse_action ) { g_debug ( "[%s] [%s] Skipping, was previously seen.", id, path ); return TRUE; } @@ -287,6 +290,13 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c g_key_file_free ( kf ); return FALSE; } + + if ( g_key_file_has_group ( kf, action ) == FALSE ) { + // No type? ignore. + g_debug ( "[%s] [%s] Invalid desktop file: No %s group", id, path, action ); + g_key_file_free ( kf ); + return FALSE; + } // Skip non Application entries. gchar *key = g_key_file_get_string ( kf, DRUN_GROUP_NAME, "Type", NULL ); if ( key == NULL ) { @@ -409,7 +419,15 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c pd->entry_list[pd->cmd_list_length].desktop_id = g_strdup ( id ); pd->entry_list[pd->cmd_list_length].app_id = g_strndup ( basename, strlen ( basename ) - strlen ( ".desktop" ) ); gchar *n = g_key_file_get_locale_string ( kf, DRUN_GROUP_NAME, "Name", NULL, NULL ); + + if ( action != DRUN_GROUP_NAME ){ + gchar *na = g_key_file_get_locale_string ( kf, action, "Name", NULL, NULL ); + gchar *l = g_strdup_printf("%s - %s", n, na); + g_free(n); + n = l; + } pd->entry_list[pd->cmd_list_length].name = n; + pd->entry_list[pd->cmd_list_length].action = DRUN_GROUP_NAME; gchar *gn = g_key_file_get_locale_string ( kf, DRUN_GROUP_NAME, "GenericName", NULL, NULL ); pd->entry_list[pd->cmd_list_length].generic_name = gn; if ( matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled ) { @@ -418,7 +436,7 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c else { pd->entry_list[pd->cmd_list_length].categories = NULL; } - pd->entry_list[pd->cmd_list_length].exec = g_key_file_get_string ( kf, DRUN_GROUP_NAME, "Exec", NULL ); + pd->entry_list[pd->cmd_list_length].exec = g_key_file_get_string ( kf, action, "Exec", NULL ); if ( matching_entry_fields[DRUN_MATCH_FIELD_COMMENT].enabled ) { pd->entry_list[pd->cmd_list_length].comment = g_key_file_get_locale_string ( kf, @@ -441,6 +459,18 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c g_hash_table_add ( pd->disabled_entries, g_strdup ( id ) ); g_debug ( "[%s] Using file %s.", id, path ); ( pd->cmd_list_length )++; + + if ( !parse_action ) { + gsize actions_length = 0; + char **actions = g_key_file_get_string_list ( kf, DRUN_GROUP_NAME, "Actions", &actions_length, NULL ); + for ( gsize iter = 0; iter < actions_length; iter++ ){ + char *new_action = g_strdup_printf("Desktop Action %s", actions[iter]); + if (! read_desktop_file ( pd, root, path, basename, new_action ) ){ + g_free ( new_action ); + } + } + g_strfreev(actions); + } return TRUE; } @@ -495,7 +525,7 @@ static void walk_dir ( DRunModePrivateData *pd, const char *root, const char *di case DT_REG: // Skip files not ending on .desktop. if ( g_str_has_suffix ( file->d_name, ".desktop" ) ) { - read_desktop_file ( pd, root, filename, file->d_name ); + read_desktop_file ( pd, root, filename, file->d_name, DRUN_GROUP_NAME ); } break; case DT_DIR: @@ -655,6 +685,9 @@ static void drun_entry_clear ( DRunModeEntry *e ) g_free ( e->name ); g_free ( e->generic_name ); g_free ( e->comment ); + if ( e->action != DRUN_GROUP_NAME ) { + g_free ( e->action ); + } g_strfreev ( e->categories ); g_key_file_free ( e->key_file ); } diff --git a/source/xrmoptions.c b/source/xrmoptions.c index 3b07cb8c..41840559 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -135,6 +135,8 @@ static XrmOption xrmOptions[] = { { xrm_String, "drun-match-fields", { .str = &config.drun_match_fields }, NULL, "Desktop entry fields to match in drun", CONFIG_DEFAULT }, + { xrm_Boolean, "drun-show-actions", { .num = &config.drun_show_actions }, NULL, + "Desktop entry show actions.", CONFIG_DEFAULT }, { xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL, "Disable history in run/ssh", CONFIG_DEFAULT }, { xrm_Boolean, "sort", { .num = &config.sort }, NULL,