diff options
author | Dave Davenport <qball@gmpclient.org> | 2015-02-12 22:16:32 +0100 |
---|---|---|
committer | Dave Davenport <qball@gmpclient.org> | 2015-02-12 22:16:32 +0100 |
commit | 605fe4911cb1683624b48d895afe6b2630e0e529 (patch) | |
tree | b2ff5ff26872d66eb5ab15b659e60c7d7c62c03d | |
parent | 9240a636d484c7f7988b212ee56f1aa2dfc12f49 (diff) |
Refactor code, split out window switcher code.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | include/window-dialog.h | 6 | ||||
-rw-r--r-- | include/x11-helper.h | 106 | ||||
-rw-r--r-- | source/rofi-i3.c | 4 | ||||
-rw-r--r-- | source/rofi.c | 191 | ||||
-rw-r--r-- | source/window-dialog.c | 479 | ||||
-rw-r--r-- | source/x11-helper.c | 186 |
7 files changed, 500 insertions, 474 deletions
diff --git a/Makefile.am b/Makefile.am index 0ff5870c..25952c86 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,6 +28,7 @@ rofi_SOURCES=\ source/xrmoptions.c\ source/dmenu-dialog.c\ source/run-dialog.c\ + source/window-dialog.c\ source/ssh-dialog.c\ source/script-dialog.c\ source/history.c\ @@ -37,6 +38,7 @@ rofi_SOURCES=\ include/rofi.h\ include/rofi-i3.h\ include/run-dialog.h\ + include/window-dialog.h\ include/ssh-dialog.h\ include/dmenu-dialog.h\ include/script-dialog.h\ diff --git a/include/window-dialog.h b/include/window-dialog.h new file mode 100644 index 00000000..e6b6f727 --- /dev/null +++ b/include/window-dialog.h @@ -0,0 +1,6 @@ +#ifndef __WINDOW_DIALOG_H__ +#define __WINDOW_DIALOG_H__ + +SwitcherMode run_switcher_window ( char **input, G_GNUC_UNUSED void *data ); + +#endif // __WINDOW_DIALOG_H__ diff --git a/include/x11-helper.h b/include/x11-helper.h index c34d907b..d0361a7a 100644 --- a/include/x11-helper.h +++ b/include/x11-helper.h @@ -1,69 +1,6 @@ #ifndef __X11_HELPER_H__ #define __X11_HELPER_H__ -// window lists -typedef struct -{ - Window *array; - void **data; - int len; -} winlist; - - -/** - * Create a window list, pre-seeded with WINLIST entries. - * - * @returns A new window list. - */ -winlist* winlist_new (); - - -/** - * @param l The winlist. - * @param w The window to find. - * - * Find the window in the list, and return the array entry. - * - * @returns -1 if failed, index is successful. - */ -int winlist_find ( winlist *l, Window w ); - -/** - * @param l The winlist entry - * - * Free the winlist. - */ -void winlist_free ( winlist *l ); - -/** - * @param l The winlist entry - * - * Empty winlist without free-ing - */ -void winlist_empty ( winlist *l ); - -/** - * @param l The winlist. - * @param w The window to add. - * @param d Data pointer. - * - * Add one entry. If Full, extend with WINLIST entries. - * - * @returns 0 if failed, 1 is successful. - */ -int winlist_append ( winlist *l, Window w, void *d ); - -/** - * @param d Display connection to X server - * @param w window - * - * Get window attributes. - * This functions uses caching. - * - * @returns a XWindowAttributes - */ -XWindowAttributes* window_get_attributes ( Display *display, Window w ); - int window_get_prop ( Display *display, Window w, Atom prop, Atom *type, int *items, @@ -85,22 +22,6 @@ int window_get_atom_prop ( Display *display, Window w, Atom atom, Atom *list, in void window_set_atom_prop ( Display *display, Window w, Atom prop, Atom *atoms, int count ); int window_get_cardinal_prop ( Display *display, Window w, Atom atom, unsigned long *list, int count ); -/** - * Create empty X11 cache for windows and windows attributes. - */ -void x11_cache_create ( void ); - -/** - * Empty the X11 cache. - * (does not free it.) - */ -void x11_cache_empty ( void ); - -/** - * Free the cache. - */ -void x11_cache_free ( void ); - /** * Window info. @@ -134,37 +55,14 @@ typedef struct int l, r, t, b; } workarea; -#define CLIENTTITLE 100 -#define CLIENTCLASS 50 -#define CLIENTNAME 50 -#define CLIENTSTATE 10 -#define CLIENTROLE 50 - -// a managable window -typedef struct -{ - Window window, trans; - XWindowAttributes xattr; - char title[CLIENTTITLE]; - char class[CLIENTCLASS]; - char name[CLIENTNAME]; - char role[CLIENTROLE]; - int states; - Atom state[CLIENTSTATE]; - workarea monitor; - int active; -} client; -// collect info on any window -// doesn't have to be a window we'll end up managing -client* window_client ( Display *display, Window win ); -int client_has_state ( client *c, Atom state ); - void monitor_active ( Display *display, workarea *mon ); int window_send_message ( Display *display, Window target, Window subject, Atom atom, unsigned long protocol, unsigned long mask, Time time ); +// find the dimensions of the monitor displaying point x,y +void monitor_dimensions ( Display *display, Screen *screen, int x, int y, workarea *mon ); /** * @param display The display. diff --git a/source/rofi-i3.c b/source/rofi-i3.c index 826df519..bcf753e7 100644 --- a/source/rofi-i3.c +++ b/source/rofi-i3.c @@ -115,6 +115,10 @@ void i3_support_focus_window ( Window id ) int i3_support_initialize ( Display *display ) { + // Free it, + g_free ( i3_socket_path ); + i3_socket_path = NULL; + // Get atom for I3_SOCKET_PATH Atom i3_sp_atom = XInternAtom ( display, "I3_SOCKET_PATH", False ); if ( i3_sp_atom != None ) { diff --git a/source/rofi.c b/source/rofi.c index eb779963..4b3fc784 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -47,7 +47,6 @@ #include "helper.h" #include "x11-helper.h" #include "rofi.h" -#include "rofi-i3.h" #include "xrmoptions.h" #include "textbox.h" // Switchers. @@ -55,6 +54,7 @@ #include "ssh-dialog.h" #include "dmenu-dialog.h" #include "script-dialog.h" +#include "window-dialog.h" #define LINE_MARGIN 3 @@ -64,9 +64,6 @@ typedef enum _MainLoopEvent ML_TIMEOUT } MainLoopEvent; -// This setting is no longer user configurable, but partial to this file: -int config_i3_mode = 0; - // Pidfile. char *pidfile = NULL; const char *cache_dir = NULL; @@ -241,49 +238,6 @@ static void menu_set_arrow_text ( int filtered_lines, int selected, int max_elem } -static int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input, - int case_sensitive, int index, void *data ) -{ - int match = 1; - winlist *ids = ( winlist * ) data; - client *c = window_client ( display, ids->array[index] ); - - if ( tokens ) { - for ( int j = 0; match && tokens[j]; j++ ) { - int test = 0; - - if ( !test && c->title[0] != '\0' ) { - char *key = token_collate_key ( c->title, case_sensitive ); - test = ( strstr ( key, tokens[j] ) != NULL ); - g_free ( key ); - } - - if ( !test && c->class[0] != '\0' ) { - char *key = token_collate_key ( c->class, case_sensitive ); - test = ( strstr ( key, tokens[j] ) != NULL ); - g_free ( key ); - } - - if ( !test && c->role[0] != '\0' ) { - char *key = token_collate_key ( c->role, case_sensitive ); - test = ( strstr ( key, tokens[j] ) != NULL ); - g_free ( key ); - } - - if ( !test && c->name[0] != '\0' ) { - char *key = token_collate_key ( c->name, case_sensitive ); - test = ( strstr ( key, tokens[j] ) != NULL ); - g_free ( key ); - } - - if ( test == 0 ) { - match = 0; - } - } - } - - return match; -} static int lev_sort ( const void *p1, const void *p2, void *arg ) { @@ -1390,141 +1344,6 @@ void error_dialog ( const char *msg ) release_keyboard ( display ); } -SwitcherMode run_switcher_window ( char **input, G_GNUC_UNUSED void *data ) -{ - Screen *screen = DefaultScreenOfDisplay ( display ); - Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) ); - SwitcherMode retv = MODE_EXIT; - // find window list - Atom type; - int nwins; - Window wins[100]; - int count = 0; - Window curr_win_id = 0; - - // Get the active window so we can highlight this. - if ( !( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, - &count, &curr_win_id, sizeof ( Window ) ) - && type == XA_WINDOW && count > 0 ) ) { - curr_win_id = 0; - } - - if ( window_get_prop ( display, root, netatoms[_NET_CLIENT_LIST_STACKING], - &type, &nwins, wins, 100 * sizeof ( Window ) ) - && type == XA_WINDOW ) { - char pattern[50]; - int i; - unsigned int classfield = 0; - unsigned long desktops = 0; - // 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... - winlist *ids = winlist_new (); - - - - // calc widths of fields - for ( i = nwins - 1; i > -1; i-- ) { - client *c; - - if ( ( c = window_client ( display, wins[i] ) ) - && !c->xattr.override_redirect - && !client_has_state ( c, netatoms[_NET_WM_STATE_SKIP_PAGER] ) - && !client_has_state ( c, netatoms[_NET_WM_STATE_SKIP_TASKBAR] ) ) { - classfield = MAX ( classfield, strlen ( c->class ) ); - - // In i3 mode, skip the i3bar completely. - if ( config_i3_mode && strstr ( c->class, "i3bar" ) != NULL ) { - continue; - } - - if ( c->window == curr_win_id ) { - c->active = TRUE; - } - winlist_append ( ids, c->window, NULL ); - } - } - - // Create pattern for printing the line. - if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_NUMBER_OF_DESKTOPS], &desktops, 1 ) ) { - desktops = 1; - } - if ( config_i3_mode ) { - sprintf ( pattern, "%%-%ds %%s", MAX ( 5, classfield ) ); - } - else{ - sprintf ( pattern, "%%-%ds %%-%ds %%s", desktops < 10 ? 1 : 2, MAX ( 5, classfield ) ); - } - char **list = g_malloc0_n ( ( ids->len + 1 ), sizeof ( char* ) ); - unsigned int lines = 0; - - // build the actual list - for ( i = 0; i < ( ids->len ); i++ ) { - Window w = ids->array[i]; - client *c; - - if ( ( c = window_client ( display, w ) ) ) { - // final line format - unsigned long wmdesktop; - char desktop[5]; - desktop[0] = 0; - char *line = g_malloc ( strlen ( c->title ) + strlen ( c->class ) + classfield + 50 ); - if ( !config_i3_mode ) { - // find client's desktop. this is zero-based, so we adjust by since most - // normal people don't think like this :-) - if ( !window_get_cardinal_prop ( display, c->window, netatoms[_NET_WM_DESKTOP], &wmdesktop, 1 ) ) { - wmdesktop = 0xFFFFFFFF; - } - - if ( wmdesktop < 0xFFFFFFFF ) { - sprintf ( desktop, "%d", (int) wmdesktop + 1 ); - } - - sprintf ( line, pattern, desktop, c->class, c->title ); - } - else{ - sprintf ( line, pattern, c->class, c->title ); - } - - list[lines++] = line; - } - } - Time time; - int selected_line = 0; - MenuReturn mretv = menu ( list, lines, input, "window:", &time, NULL, - window_match, ids, &selected_line, config.levenshtein_sort ); - - if ( mretv == MENU_NEXT ) { - retv = NEXT_DIALOG; - } - else if ( mretv == MENU_PREVIOUS ) { - retv = PREVIOUS_DIALOG; - } - else if ( mretv == MENU_QUICK_SWITCH ) { - retv = selected_line; - } - else if ( ( mretv == MENU_OK || mretv == MENU_CUSTOM_INPUT ) && list[selected_line] ) { - if ( config_i3_mode ) { - // Hack for i3. - i3_support_focus_window ( ids->array[selected_line] ); - } - else{ - // Change to the desktop of the selected window/client. - // TODO: get rid of strtol - window_send_message ( display, root, root, netatoms[_NET_CURRENT_DESKTOP], strtol ( list[selected_line], NULL, 10 ) - 1, - SubstructureNotifyMask | SubstructureRedirectMask, time ); - XSync ( display, False ); - - window_send_message ( display, root, ids->array[selected_line], netatoms[_NET_ACTIVE_WINDOW], 2, // 2 = pager - SubstructureNotifyMask | SubstructureRedirectMask, time ); - } - } - - g_strfreev ( list ); - winlist_free ( ids ); - } - - return retv; -} /** * Start dmenu mode. @@ -1683,9 +1502,6 @@ static void cleanup () XCloseDisplay ( display ); } } - x11_cache_free (); - - i3_support_free_internals (); // Cleaning up memory allocated by the Xresources file. config_xresource_free (); @@ -1883,9 +1699,6 @@ int main ( int argc, char *argv[] ) x11_setup ( display ); - // Check for i3 - config_i3_mode = i3_support_initialize ( display ); - char *msg = NULL; if ( find_arg_str ( argc, argv, "-e", &( msg ) ) ) { show_error_message ( msg ); @@ -1992,8 +1805,6 @@ int main ( int argc, char *argv[] ) // catching global key presses. for (;; ) { XEvent ev; - // caches only live for a single event - x11_cache_empty (); // block and wait for something XNextEvent ( display, &ev ); diff --git a/source/window-dialog.c b/source/window-dialog.c new file mode 100644 index 00000000..993b885c --- /dev/null +++ b/source/window-dialog.c @@ -0,0 +1,479 @@ +/** + * rofi + * + * MIT/X11 License + * Copyright 2013-2014 Qball Cow <qball@gmpclient.org> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <X11/X.h> + +#include <unistd.h> +#include <limits.h> +#include <signal.h> +#include <sys/types.h> +#include <dirent.h> +#include <strings.h> +#include <string.h> +#include <errno.h> +#include <X11/X.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include <X11/XKBlib.h> + +#include "rofi.h" +#include "helper.h" +#include "x11-helper.h" +#include "rofi-i3.h" +#include "window-dialog.h" + + +#define WINLIST 32 + +#define CLIENTTITLE 100 +#define CLIENTCLASS 50 +#define CLIENTNAME 50 +#define CLIENTSTATE 10 +#define CLIENTROLE 50 + +// a managable window +typedef struct +{ + Window window, trans; + XWindowAttributes xattr; + char title[CLIENTTITLE]; + char class[CLIENTCLASS]; + char name[CLIENTNAME]; + char role[CLIENTROLE]; + int states; + Atom state[CLIENTSTATE]; + workarea monitor; + int active; +} client; +// TODO +extern Display *display; +// window lists +typedef struct +{ + Window *array; + void **data; + int len; +} winlist; + +winlist *cache_client = NULL; +winlist *cache_xattr = NULL; + +/** + * Create a window list, pre-seeded with WINLIST entries. + * + * @returns A new window list. + */ +static winlist* winlist_new () +{ + winlist *l = g_malloc ( sizeof ( winlist ) ); + l->len = 0; + l->array = g_malloc_n ( WINLIST + 1, sizeof ( Window ) ); + l->data = g_malloc_n ( WINLIST + 1, sizeof ( void* ) ); + return l; +} + +/** + * @param l The winlist. + * @param w The window to add. + * @param d Data pointer. + * + * Add one entry. If Full, extend with WINLIST entries. + * + * @returns 0 if failed, 1 is successful. + */ +static int winlist_append ( winlist *l, Window w, void *d ) +{ + if ( l->len > 0 && !( l->len % WINLIST ) ) { + l->array = g_realloc ( l->array, sizeof ( Window ) * ( l->len + WINLIST + 1 ) ); + l->data = g_realloc ( l->data, sizeof ( void* ) * ( l->len + WINLIST + 1 ) ); + } + // Make clang-check happy. + // TODO: make clang-check clear this should never be 0. + if ( l->data == NULL || l->array == NULL ) { + return 0; + } + + l->data[l->len] = d; + l->array[l->len++] = w; + return l->len - 1; +} + +static void winlist_empty ( winlist *l ) +{ + while ( l->len > 0 ) { + g_free ( l->data[--( l->len )] ); + } +} + +/** + * @param l The winlist entry + * + * Free the winlist. + */ +static void winlist_free ( winlist *l ) +{ + if ( l != NULL ) { + winlist_empty ( l ); + g_free ( l->array ); + g_free ( l->data ); + g_free ( l ); + } +} + +/** + * @param l The winlist. + * @param w The window to find. + * + * Find the window in the list, and return the array entry. + * + * @returns -1 if failed, index is successful. + */ +static int winlist_find ( winlist *l, Window w ) +{ +// iterate backwards. theory is: windows most often accessed will be +// nearer the end. testing with kcachegrind seems to support this... + int i; + + for ( i = ( l->len - 1 ); i >= 0; i-- ) { + if ( l->array[i] == w ) { + return i; + } + } + + return -1; +} +/** + * Create empty X11 cache for windows and windows attributes. + */ +static void x11_cache_create ( void ) +{ + cache_client = winlist_new (); + cache_xattr = winlist_new (); +} + +/** + * Free the cache. + */ +static void x11_cache_free ( void ) +{ + winlist_free ( cache_xattr ); + winlist_free ( cache_client ); +} + +/** + * @param d Display connection to X server + * @param w window + * + * Get window attributes. + * This functions uses caching. + * + * @returns a XWindowAttributes + */ +static XWindowAttributes* window_get_attributes ( Display *display, Window w ) +{ + int idx = winlist_find ( cache_xattr, w ); + + if ( idx < 0 ) { + XWindowAttributes *cattr = g_malloc ( sizeof ( XWindowAttributes ) ); + + if ( XGetWindowAttributes ( display, w, cattr ) ) { + winlist_append ( cache_xattr, w, cattr ); + return cattr; + } + + g_free ( cattr ); + return NULL; + } + + return cache_xattr->data[idx]; +} +// _NET_WM_STATE_* +static int client_has_state ( client *c, Atom state ) +{ + for ( int i = 0; i < c->states; i++ ) { + if ( c->state[i] == state ) { + return 1; + } + } + + return 0; +} + +static client* window_client ( Display *display, Window win ) +{ + if ( win == None ) { + return NULL; + } + + int idx = winlist_find ( cache_client, win ); + + if ( idx >= 0 ) { + return cache_client->data[idx]; + } + + // if this fails, we're up that creek + XWindowAttributes *attr = window_get_attributes ( display, win ); + + if ( !attr ) { + return NULL; + } + + client *c = g_malloc0 ( sizeof ( client ) ); + c->window = win; + + // copy xattr so we don't have to care when stuff is freed + memmove ( &c->xattr, attr, sizeof ( XWindowAttributes ) ); + XGetTransientForHint ( display, win, &c->trans ); + + c->states = window_get_atom_prop ( display, win, netatoms[_NET_WM_STATE], c->state, CLIENTSTATE ); + + char *name; + + if ( ( name = window_get_text_prop ( display, c->window, netatoms[_NET_WM_NAME] ) ) && name ) { + snprintf ( c->title, CLIENTTITLE, "%s", name ); + g_free ( name ); + } + else if ( XFetchName ( display, c->window, &name ) ) { + snprintf ( c->title, CLIENTTITLE, "%s", name ); + XFree ( name ); + } + + name = window_get_text_prop ( display, c->window, XInternAtom ( display, "WM_WINDOW_ROLE", False ) ); + + if ( name != NULL ) { + snprintf ( c->role, CLIENTROLE, "%s", name ); + XFree ( name ); + } + + XClassHint chint; + + if ( XGetClassHint ( display, c->window, &chint ) ) { + snprintf ( c->class, CLIENTCLASS, "%s", chint.res_class ); + snprintf ( c->name, CLIENTNAME, "%s", chint.res_name ); + XFree ( chint.res_class ); + XFree ( chint.res_name ); + } + + monitor_dimensions ( display, c->xattr.screen, c->xattr.x, c->xattr.y, &c->monitor ); + winlist_append ( cache_client, c->window, c ); + return c; +} + + + +static int window_match ( char **tokens, __attribute__( ( unused ) ) const char *input, + int case_sensitive, int index, void *data ) +{ + int match = 1; + winlist *ids = ( winlist * ) data; + client *c = window_client ( display, ids->array[index] ); + + if ( tokens ) { + for ( int j = 0; match && tokens[j]; j++ ) { + int test = 0; + + if ( !test && c->title[0] != '\0' ) { + char *key = token_collate_key ( c->title, case_sensitive ); + test = ( strstr ( key, tokens[j] ) != NULL ); + g_free ( key ); + } + + if ( !test && c->class[0] != '\0' ) { + char *key = token_collate_key ( c->class, case_sensitive ); + test = ( strstr ( key, tokens[j] ) != NULL ); + g_free ( key ); + } + + if ( !test && c->role[0] != '\0' ) { + char *key = token_collate_key ( c->role, case_sensitive ); + test = ( strstr ( key, tokens[j] ) != NULL ); + g_free ( key ); + } + + if ( !test && c->name[0] != '\0' ) { + char *key = token_collate_key ( c->name, case_sensitive ); + test = ( strstr ( key, tokens[j] ) != NULL ); + g_free ( key ); + } + + if ( test == 0 ) { + match = 0; + } + } + } + + return match; +} + + +SwitcherMode run_switcher_window ( char **input, G_GNUC_UNUSED void *data ) +{ + Screen *screen = DefaultScreenOfDisplay ( display ); + Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) ); + SwitcherMode retv = MODE_EXIT; + // find window list + Atom type; + int nwins; + Window wins[100]; + int count = 0; + Window curr_win_id = 0; + // Create cache + + x11_cache_create (); + // Check for i3 + int config_i3_mode = i3_support_initialize ( display ); + + // Get the active window so we can highlight this. + if ( !( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, + &count, &curr_win_id, sizeof ( Window ) ) + && type == XA_WINDOW && count > 0 ) ) { + curr_win_id = 0; + } + + if ( window_get_prop ( display, root, netatoms[_NET_CLIENT_LIST_STACKING], + &type, &nwins, wins, 100 * sizeof ( Window ) ) + && type == XA_WINDOW ) { + char pattern[50]; + int i; + unsigned int classfield = 0; + unsigned long desktops = 0; + // 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... + winlist *ids = winlist_new (); + + + + // calc widths of fields + for ( i = nwins - 1; i > -1; i-- ) { + client *c; + + if ( ( c = window_client ( display, wins[i] ) ) + && !c->xattr.override_redirect + && !client_has_state ( c, netatoms[_NET_WM_STATE_SKIP_PAGER] ) + && !client_has_state ( c, netatoms[_NET_WM_STATE_SKIP_TASKBAR] ) ) { + classfield = MAX ( classfield, strlen ( c->class ) ); + + // In i3 mode, skip the i3bar completely. + if ( config_i3_mode && strstr ( c->class, "i3bar" ) != NULL ) { + continue; + } + + if ( c->window == curr_win_id ) { + c->active = TRUE; + } + winlist_append ( ids, c->window, NULL ); + } + } + + // Create pattern for printing the line. + if ( !window_get_cardinal_prop ( display, root, netatoms[_NET_NUMBER_OF_DESKTOPS], &desktops, 1 ) ) { + desktops = 1; + } + if ( config_i3_mode ) { + sprintf ( pattern, "%%-%ds %%s", MAX ( 5, classfield ) ); + } + else{ + sprintf ( pattern, "%%-%ds %%-%ds %%s", desktops < 10 ? 1 : 2, MAX ( 5, classfield ) ); + } + char **list = g_malloc0_n ( ( ids->len + 1 ), sizeof ( char* ) ); + unsigned int lines = 0; + + // build the actual list + for ( i = 0; i < ( ids->len ); i++ ) { + Window w = ids->array[i]; + client *c; + + if ( ( c = window_client ( display, w ) ) ) { + // final line format + unsigned long wmdesktop; + char desktop[5]; + desktop[0] = 0; + char *line = g_malloc ( strlen ( c->title ) + strlen ( c->class ) + classfield + 50 ); + if ( !config_i3_mode ) { + // find client's desktop. this is zero-based, so we adjust by since most + // normal people don't think like this :-) + if ( !window_get_cardinal_prop ( display, c->window, netatoms[_NET_WM_DESKTOP], &wmdesktop, 1 ) ) { + wmdesktop = 0xFFFFFFFF; + } + + if ( wmdesktop < 0xFFFFFFFF ) { + sprintf ( desktop, "%d", (int) wmdesktop + 1 ); + } + + sprintf ( line, pattern, desktop, c->class, c->title ); + } + else{ + sprintf ( line, pattern, c->class, c->title ); + } + + list[lines++] = line; + } + } + Time time; + int selected_line = 0; + MenuReturn mretv = menu ( list, lines, input, "window:", &time, NULL, + window_match, ids, &selected_line, config.levenshtein_sort ); + + if ( mretv == MENU_NEXT ) { + retv = NEXT_DIALOG; + } + else if ( mretv == MENU_PREVIOUS ) { + retv = PREVIOUS_DIALOG; + } + else if ( mretv == MENU_QUICK_SWITCH ) { + retv = selected_line; + } + else if ( ( mretv == MENU_OK || mretv == MENU_CUSTOM_INPUT ) && list[selected_line] ) { + if ( config_i3_mode ) { + // Hack for i3. + i3_support_focus_window ( ids->array[selected_line] ); + } + else{ + // Change to the desktop of the selected window/client. + // TODO: get rid of strtol + window_send_message ( display, root, root, netatoms[_NET_CURRENT_DESKTOP], strtol ( list[selected_line], NULL, 10 ) - 1, + SubstructureNotifyMask | SubstructureRedirectMask, time ); + XSync ( display, False ); + + window_send_message ( display, root, ids->array[selected_line], netatoms[_NET_ACTIVE_WINDOW], 2, // 2 = pager + SubstructureNotifyMask | SubstructureRedirectMask, time ); + } + } + + g_strfreev ( list ); + winlist_free ( ids ); + } + + i3_support_free_internals (); + x11_cache_free (); + return retv; +} diff --git a/source/x11-helper.c b/source/x11-helper.c index b514825d..db3187bf 100644 --- a/source/x11-helper.c +++ b/source/x11-helper.c @@ -20,92 +20,9 @@ #define INTERSECT( x, y, w, h, x1, y1, w1, h1 ) ( OVERLAP ( ( x ), ( w ), ( x1 ), ( w1 ) ) && OVERLAP ( ( y ), ( h ), ( y1 ), ( h1 ) ) ) #include "x11-helper.h" -#define WINLIST 32 - // Mask indicating num-lock. unsigned int NumlockMask = 0; -winlist *cache_client = NULL; -winlist *cache_xattr = NULL; - -winlist* winlist_new () -{ - winlist *l = g_malloc ( sizeof ( winlist ) ); - l->len = 0; - l->array = g_malloc_n ( WINLIST + 1, sizeof ( Window ) ); - l->data = g_malloc_n ( WINLIST + 1, sizeof ( void* ) ); - return l; -} - -int winlist_append ( winlist *l, Window w, void *d ) -{ - if ( l->len > 0 && !( l->len % WINLIST ) ) { - l->array = g_realloc ( l->array, sizeof ( Window ) * ( l->len + WINLIST + 1 ) ); - l->data = g_realloc ( l->data, sizeof ( void* ) * ( l->len + WINLIST + 1 ) ); - } - // Make clang-check happy. - // TODO: make clang-check clear this should never be 0. - if ( l->data == NULL || l->array == NULL ) { - return 0; - } - - l->data[l->len] = d; - l->array[l->len++] = w; - return l->len - 1; -} - -void winlist_empty ( winlist *l ) -{ - while ( l->len > 0 ) { - g_free ( l->data[--( l->len )] ); - } -} - -void winlist_free ( winlist *l ) -{ - if ( l != NULL ) { - winlist_empty ( l ); - g_free ( l->array ); - g_free ( l->data ); - g_free ( l ); - } -} - -int winlist_find ( winlist *l, Window w ) -{ -// iterate backwards. theory is: windows most often accessed will be -// nearer the end. testing with kcachegrind seems to support this... - int i; - - for ( i = ( l->len - 1 ); i >= 0; i-- ) { - if ( l->array[i] == w ) { - return i; - } - } - - return -1; -} - - -XWindowAttributes* window_get_attributes ( Display *display, Window w ) -{ - int idx = winlist_find ( cache_xattr, w ); - - if ( idx < 0 ) { - XWindowAttributes *cattr = g_malloc ( sizeof ( XWindowAttributes ) ); - - if ( XGetWindowAttributes ( displa |