diff --git a/config/config.c b/config/config.c index 82ab987c..d27e043b 100644 --- a/config/config.c +++ b/config/config.c @@ -128,4 +128,5 @@ Settings config = { .scrollbar_width = 8, .scroll_method = 0, .fake_background = "screenshot", + .window_format = "w c t", }; diff --git a/include/settings.h b/include/settings.h index ff9393a5..d08abd88 100644 --- a/include/settings.h +++ b/include/settings.h @@ -131,6 +131,8 @@ typedef struct unsigned int scroll_method; /** Background type */ char *fake_background; + + char *window_format; } Settings; /** Global Settings structure. */ extern Settings config; diff --git a/include/textbox.h b/include/textbox.h index a7619f7d..455904f8 100644 --- a/include/textbox.h +++ b/include/textbox.h @@ -39,15 +39,15 @@ typedef struct typedef enum { - TB_AUTOHEIGHT = 1 << 0, - TB_AUTOWIDTH = 1 << 1, - TB_LEFT = 1 << 16, - TB_RIGHT = 1 << 17, - TB_CENTER = 1 << 18, - TB_EDITABLE = 1 << 19, - TB_MARKUP = 1 << 20, - TB_WRAP = 1 << 21, - TB_PASSWORD = 1 << 22, + TB_AUTOHEIGHT = 1 << 0, + TB_AUTOWIDTH = 1 << 1, + TB_LEFT = 1 << 16, + TB_RIGHT = 1 << 17, + TB_CENTER = 1 << 18, + TB_EDITABLE = 1 << 19, + TB_MARKUP = 1 << 20, + TB_WRAP = 1 << 21, + TB_PASSWORD = 1 << 22, } TextboxFlags; typedef enum diff --git a/source/dialogs/ssh.c b/source/dialogs/ssh.c index 9cc75543..331e5431 100644 --- a/source/dialogs/ssh.c +++ b/source/dialogs/ssh.c @@ -198,7 +198,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length ) // Reading one line per time. while ( getline ( &buffer, &buffer_length, fd ) > 0 ) { // Evaluate one line. - unsigned int index = 0, ti = 0; + unsigned int index = 0, ti = 0; char *token = buffer; // Tokenize it. diff --git a/source/dialogs/window.c b/source/dialogs/window.c index a931fdbf..08cb090c 100644 --- a/source/dialogs/window.c +++ b/source/dialogs/window.c @@ -73,6 +73,8 @@ typedef struct int active; int demands; long hint_flags; + uint32_t wmdesktop; + char *wmdesktopstr; } client; // window lists @@ -83,6 +85,21 @@ typedef struct int len; } winlist; +typedef struct +{ + unsigned int id; + winlist *ids; + int config_i3_mode; + // Current window. + unsigned int index; + char *cache; + unsigned int wmdn_len; + unsigned int clf_len; + unsigned int name_len; + unsigned int title_len; + unsigned int role_len; +} ModeModePrivateData; + winlist *cache_client = NULL; /** @@ -134,6 +151,7 @@ static void winlist_empty ( winlist *l ) g_free ( c->class ); g_free ( c->name ); g_free ( c->role ); + g_free ( c->wmdesktopstr ); g_free ( c ); } } @@ -235,7 +253,7 @@ static int client_has_window_type ( client *c, xcb_atom_t type ) return 0; } -static client* window_client ( xcb_window_t win ) +static client* window_client ( ModeModePrivateData *pd, xcb_window_t win ) { if ( win == XCB_WINDOW_NONE ) { return NULL; @@ -277,14 +295,17 @@ static client* window_client ( xcb_window_t win ) if ( c->title == NULL ) { c->title = window_get_text_prop ( c->window, XCB_ATOM_WM_NAME ); } + pd->title_len = MAX ( c->title ? strlen ( c->title ) : 0, pd->title_len ); - c->role = window_get_text_prop ( c->window, netatoms[WM_WINDOW_ROLE] ); + c->role = window_get_text_prop ( c->window, netatoms[WM_WINDOW_ROLE] ); + pd->role_len = MAX ( c->role ? strlen ( c->role ) : 0, pd->role_len ); cky = xcb_icccm_get_wm_class ( xcb->connection, c->window ); xcb_icccm_get_wm_class_reply_t wcr; if ( xcb_icccm_get_wm_class_reply ( xcb->connection, cky, &wcr, NULL ) ) { - c->class = rofi_latin_to_utf8_strdup ( wcr.class_name, -1 ); - c->name = rofi_latin_to_utf8_strdup ( wcr.instance_name, -1 ); + c->class = rofi_latin_to_utf8_strdup ( wcr.class_name, -1 ); + c->name = rofi_latin_to_utf8_strdup ( wcr.instance_name, -1 ); + pd->name_len = MAX ( c->name ? strlen ( c->name ) : 0, pd->name_len ); xcb_icccm_get_wm_class_reply_wipe ( &wcr ); } @@ -298,19 +319,6 @@ static client* window_client ( xcb_window_t win ) g_free ( attr ); return c; } - -typedef struct -{ - unsigned int id; - char **cmd_list; - unsigned int cmd_list_length; - winlist *ids; - int config_i3_mode; - // Current window. - unsigned int index; - char *cache; -} ModeModePrivateData; - static int window_match ( const Mode *sw, GRegex **tokens, unsigned int index ) { ModeModePrivateData *rmpd = (ModeModePrivateData *) mode_get_private_data ( sw ); @@ -357,7 +365,7 @@ static int window_match ( const Mode *sw, GRegex **tokens, unsigned int index ) static unsigned int window_mode_get_num_entries ( const Mode *sw ) { const ModeModePrivateData *pd = (const ModeModePrivateData *) mode_get_private_data ( sw ); - return pd->cmd_list_length; + return pd->ids->len; } /** * Small helper function to find the right entry in the ewmh reply. @@ -415,24 +423,27 @@ static void _window_mode_load_data ( Mode *sw, unsigned int cd ) } } if ( nwins > 0 ) { - char pattern[50]; - int i; - unsigned int classfield = 0; - unsigned int desktops = 0; + int i; // windows we actually display. May be slightly different to _NET_CLIENT_LIST_STACKING // if we happen to have a window destroyed while we're working... pd->ids = winlist_new (); + xcb_get_property_cookie_t c = xcb_ewmh_get_desktop_names ( &xcb->ewmh, xcb->screen_nbr ); + xcb_ewmh_get_utf8_strings_reply_t names; + int has_names = FALSE; + if ( xcb_ewmh_get_desktop_names_reply ( &xcb->ewmh, c, &names, NULL ) ) { + has_names = TRUE; + } // calc widths of fields for ( i = nwins - 1; i > -1; i-- ) { - client *c = window_client ( wins[i] ); + client *c = window_client ( pd, wins[i] ); if ( ( c != NULL ) && !c->xattr.override_redirect && !client_has_window_type ( c, xcb->ewmh._NET_WM_WINDOW_TYPE_DOCK ) && !client_has_window_type ( c, xcb->ewmh._NET_WM_WINDOW_TYPE_DESKTOP ) && !client_has_state ( c, xcb->ewmh._NET_WM_STATE_SKIP_PAGER ) && !client_has_state ( c, xcb->ewmh._NET_WM_STATE_SKIP_TASKBAR ) ) { - classfield = MAX ( classfield, ( c->class != NULL ) ? ( strlen ( c->class ) ) : 0 ); + pd->clf_len = MAX ( pd->clf_len, ( c->class != NULL ) ? ( strlen ( c->class ) ) : 0 ); if ( client_has_state ( c, xcb->ewmh._NET_WM_STATE_DEMANDS_ATTENTION ) ) { c->demands = TRUE; @@ -444,85 +455,40 @@ static void _window_mode_load_data ( Mode *sw, unsigned int cd ) if ( c->window == curr_win_id ) { c->active = TRUE; } + // find client's desktop. + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *r; + + c->wmdesktop = 0xFFFFFFFF; + cookie = + xcb_get_property ( xcb->connection, 0, c->window, xcb->ewmh._NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 0, + 1 ); + r = xcb_get_property_reply ( xcb->connection, cookie, NULL ); + if ( r ) { + if ( r->type == XCB_ATOM_CARDINAL ) { + c->wmdesktop = *( (uint32_t *) xcb_get_property_value ( r ) ); + } + free ( r ); + } + if ( c->wmdesktop != 0xFFFFFFFF ) { + if ( has_names ) { + c->wmdesktopstr = g_strdup ( _window_name_list_entry ( names.strings, names.strings_len, c->wmdesktop ) ); + } + else { + c->wmdesktopstr = g_strdup_printf ( "%u", (uint32_t) c->wmdesktop ); + } + } + else { + c->wmdesktopstr = g_strdup ( "" ); + } + pd->wmdn_len = MAX ( pd->wmdn_len, strlen ( c->wmdesktopstr ) ); + if ( cd && c->wmdesktop != current_desktop ) { + continue; + } winlist_append ( pd->ids, c->window, NULL ); } } - // Create pattern for printing the line. - xcb_get_property_cookie_t c = xcb_ewmh_get_number_of_desktops ( &xcb->ewmh, xcb->screen_nbr ); - if ( !xcb_ewmh_get_number_of_desktops_reply ( &xcb->ewmh, c, &desktops, NULL ) ) { - desktops = 1; - } - - if ( pd->config_i3_mode ) { - snprintf ( pattern, 50, "%%-%ds %%s", MAX ( 5, classfield ) ); - } - else{ - snprintf ( pattern, 50, "%%-%ds %%-%ds %%s", desktops < 10 ? 1 : 2, - MAX ( 5, classfield ) ); - } - pd->cmd_list = g_malloc0_n ( ( pd->ids->len + 1 ), sizeof ( char* ) ); - - c = xcb_ewmh_get_desktop_names ( &xcb->ewmh, xcb->screen_nbr ); - xcb_ewmh_get_utf8_strings_reply_t names; - int has_names = FALSE; - if ( xcb_ewmh_get_desktop_names_reply ( &xcb->ewmh, c, &names, NULL ) ) { - has_names = TRUE; - } - // build the actual list - for ( i = 0; i < ( pd->ids->len ); i++ ) { - xcb_window_t w = pd->ids->array[i]; - client *c; - - if ( ( c = window_client ( w ) ) ) { - // final line format - char *desktop = NULL; - char *line = NULL; - if ( !pd->config_i3_mode ) { - uint32_t wmdesktop = 0; - // find client's desktop. - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *r; - - cookie = - xcb_get_property ( xcb->connection, 0, c->window, xcb->ewmh._NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 0, - 1 ); - r = xcb_get_property_reply ( xcb->connection, cookie, NULL ); - if ( r && r->type == XCB_ATOM_CARDINAL ) { - wmdesktop = *( (uint32_t *) xcb_get_property_value ( r ) ); - } - if ( r && r->type != XCB_ATOM_CARDINAL ) { - // Assume the client is on all desktops. - wmdesktop = 0xFFFFFFFF; - } - else if ( cd && wmdesktop != current_desktop ) { - g_free ( line ); - free ( r ); - continue; - } - free ( r ); - - if ( wmdesktop < 0xFFFFFFFF ) { - if ( has_names ) { - desktop = g_strdup_printf ( "%s", _window_name_list_entry ( names.strings, names.strings_len, wmdesktop ) ); - } - else { - desktop = g_strdup_printf ( "%u", (uint32_t) wmdesktop ); - } - } - else { - desktop = g_strdup ( "" ); - } - - line = g_strdup_printf ( pattern, desktop, c->class ? c->class : "", c->title ? c->title : "" ); - } - else{ - line = g_strdup_printf ( pattern, c->class ? c->class : "", c->title ? c->title : "" ); - } - g_free ( desktop ); - pd->cmd_list[pd->cmd_list_length++] = line; - } - } if ( has_names ) { xcb_ewmh_get_utf8_strings_reply_wipe ( &names ); } @@ -588,7 +554,7 @@ static ModeMode window_mode_result ( Mode *sw, int mretv, G_GNUC_UNUSED char **i else if ( ( mretv & MENU_QUICK_SWITCH ) == MENU_QUICK_SWITCH ) { retv = ( mretv & MENU_LOWER_MASK ); } - else if ( ( mretv & ( MENU_OK ) ) && rmpd->cmd_list[selected_line] ) { + else if ( ( mretv & ( MENU_OK ) ) ) { if ( mretv & MENU_CUSTOM_ACTION ) { act_on_window ( rmpd->ids->array[selected_line] ); } @@ -653,7 +619,6 @@ static void window_mode_destroy ( Mode *sw ) { ModeModePrivateData *rmpd = (ModeModePrivateData *) mode_get_private_data ( sw ); if ( rmpd != NULL ) { - g_strfreev ( rmpd->cmd_list ); winlist_free ( rmpd->ids ); i3_support_free_internals (); x11_cache_free (); @@ -662,17 +627,52 @@ static void window_mode_destroy ( Mode *sw ) mode_set_private_data ( sw, NULL ); } } +static char * _generate_display_string ( const ModeModePrivateData *pd, client *c ) +{ + GString * str = g_string_new ( "" ); + const char *v = config.window_format; + ssize_t l = strlen ( v ); + + for ( ssize_t j = 0; j < l; j++ ) { + if ( v[j] == 'w' ) { + g_string_append_printf ( str, "%-*s", pd->wmdn_len, c->wmdesktopstr ); + } + else if ( v[j] == 'c' ) { + g_string_append_printf ( str, "%-*s", pd->clf_len, c->class ? c->class : "" ); + } + else if ( v[j] == 't' ) { + g_string_append_printf ( str, "%-*s", pd->title_len, c->title ? c->title : "" ); + } + else if ( v[j] == 'n' ) { + g_string_append_printf ( str, "%-*s", pd->name_len, c->name ? c->name : "" ); + } + else if ( v[j] == 'r' ) { + g_string_append_printf ( str, "%-*s", pd->role_len, c->role ? c->role : "" ); + } + else { + g_string_append_c ( str, v[j] ); + } + } + + char *r = str->str; + g_string_free ( str, FALSE ); + return r; +} static char *_get_display_value ( const Mode *sw, unsigned int selected_line, int *state, int get_entry ) { ModeModePrivateData *rmpd = mode_get_private_data ( sw ); - if ( window_client ( rmpd->ids->array[selected_line] )->demands ) { + client *c = window_client ( rmpd, rmpd->ids->array[selected_line] ); + if ( c == NULL ) { + return get_entry ? g_strdup ( "Window has fanished" ) : NULL; + } + if ( c->demands ) { *state |= URGENT; } - if ( window_client ( rmpd->ids->array[selected_line] )->active ) { + if ( c->active ) { *state |= ACTIVE; } - return get_entry ? g_strdup ( rmpd->cmd_list[selected_line] ) : NULL; + return get_entry ? _generate_display_string ( rmpd, c ) : NULL; } #include "mode-private.h" diff --git a/source/helper.c b/source/helper.c index 4c0f5bca..684256f8 100644 --- a/source/helper.c +++ b/source/helper.c @@ -197,7 +197,7 @@ GRegex **tokenize ( const char *input, int case_sensitive ) } char *saveptr = NULL, *token; - GRegex **retv = NULL; + GRegex **retv = NULL; if ( !config.tokenize ) { retv = g_malloc0 ( sizeof ( GRegex* ) * 2 ); retv[0] = (GRegex *) create_regex ( input, case_sensitive ); diff --git a/source/rofi.c b/source/rofi.c index eed87aa4..acc95107 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -74,9 +74,9 @@ struct xkb_stuff xkb = { .keymap = NULL, .state = NULL, .compose = { - .table = NULL, - .state = NULL -} + .table = NULL, + .state = NULL + } }; char *config_path = NULL; // Array of modi. @@ -441,22 +441,22 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id ); break; case XCB_XKB_STATE_NOTIFY: - { - 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 ( ); - } - break; + { + 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 ( ); } + break; + } } return G_SOURCE_CONTINUE; } diff --git a/source/xrmoptions.c b/source/xrmoptions.c index 6d2f99c9..f8eb4c72 100644 --- a/source/xrmoptions.c +++ b/source/xrmoptions.c @@ -173,6 +173,8 @@ static XrmOption xrmOptions[] = { "Scrolling method. (0: Page, 1: Centered)" }, { xrm_String, "fake-background", { .str = &config.fake_background }, NULL, "Background to use for fake transparency. (background or screenshot)" }, + { xrm_String, "window-format", { .str = &config.window_format }, NULL, + "Window Format. w (desktop name), t (title), n (name), r (role), c (class)" }, }; // Dynamic options.