Refactor code, split out window switcher code.

This commit is contained in:
Dave Davenport 2015-02-12 22:16:32 +01:00
parent 9240a636d4
commit 605fe4911c
7 changed files with 500 additions and 474 deletions

View File

@ -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\

6
include/window-dialog.h Normal file
View File

@ -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__

View File

@ -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.

View File

@ -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 ) {

View File

@ -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 );

479
source/window-dialog.c Normal file
View File

@ -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;
}

View File

@ -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 ( display, w, cattr ) ) {
winlist_append ( cache_xattr, w, cattr );
return cattr;
}
g_free ( cattr );
return NULL;
}
return cache_xattr->data[idx];
}
// retrieve a property of any type from a window
int window_get_prop ( Display *display, Window w, Atom prop,
Atom *type, int *items,
@ -190,26 +107,8 @@ int window_get_cardinal_prop ( Display *display, Window w, Atom atom, unsigned l
}
void x11_cache_create ( void )
{
cache_client = winlist_new ();
cache_xattr = winlist_new ();
}
void x11_cache_empty ( void )
{
winlist_empty ( cache_xattr );
winlist_empty ( cache_client );
}
void x11_cache_free ( void )
{
winlist_free ( cache_xattr );
winlist_free ( cache_client );
}
// find the dimensions of the monitor displaying point x,y
static void monitor_dimensions ( Display *display, Screen *screen, int x, int y, workarea *mon )
void monitor_dimensions ( Display *display, Screen *screen, int x, int y, workarea *mon )
{
memset ( mon, 0, sizeof ( workarea ) );
mon->w = WidthOfScreen ( screen );
@ -236,78 +135,6 @@ static void monitor_dimensions ( Display *display, Screen *screen, int x, int y,
}
}
// _NET_WM_STATE_*
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;
}
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;
}
/**
* @param x The x position of the mouse [out]
* @param y The y position of the mouse [out]
@ -346,12 +173,12 @@ void monitor_active ( Display *display, workarea *mon )
int count;
if ( window_get_prop ( display, root, netatoms[_NET_ACTIVE_WINDOW], &type, &count, &id, sizeof ( Window ) )
&& type == XA_WINDOW && count > 0 ) {
XWindowAttributes *attr = window_get_attributes ( display, id );
if ( attr != NULL ) {
XWindowAttributes attr;
if ( XGetWindowAttributes ( display, id, &attr ) ) {
Window junkwin;
if ( XTranslateCoordinates ( display, id, attr->root,
-attr->border_width,
-attr->border_width,
if ( XTranslateCoordinates ( display, id, attr.root,
-attr.border_width,
-attr.border_width,
&x, &y, &junkwin ) == True ) {
monitor_dimensions ( display, screen, x, y, mon );
return;
@ -551,6 +378,5 @@ void x11_setup ( Display *display )
// determine numlock mask so we can bind on keys with and without it
x11_figure_out_numlock_mask ( display );
x11_cache_create ();
x11_create_frequently_used_atoms ( display );
}