changeset 1282:e2b603437d84

Merged in default (pull request #62) Hide GntWM internals Approved-by: Gary Kramlich
author Gary Kramlich <grim@reaperworld.com>
date Fri, 10 May 2019 23:31:00 +0000
parents 7f143638ae69 (current diff) b90962558cfa (diff)
children 33790ead582a 2c1e3c534dbc
files
diffstat 8 files changed, 629 insertions(+), 283 deletions(-) [+]
line wrap: on
line diff
--- a/gntmain.c	Fri May 10 23:13:35 2019 +0000
+++ b/gntmain.c	Fri May 10 23:31:00 2019 +0000
@@ -52,6 +52,7 @@
 
 #include "gntboxprivate.h"
 #include "gntmenuprivate.h"
+#include "gntwmprivate.h"
 #include "gntwsprivate.h"
 
 #include "gntwidgetprivate.h"
@@ -164,7 +165,8 @@
 	GntWidget *widget = NULL;
 	PANEL *p = NULL;
 
-	if (gnt_ws_is_empty(wm->cws) || buffer[0] != 27) {
+	if (gnt_ws_is_empty(gnt_wm_get_current_workspace(wm)) ||
+	    buffer[0] != 27) {
 		return FALSE;
 	}
 
@@ -223,9 +225,11 @@
 		return TRUE;
 
 	if (event == GNT_LEFT_MOUSE_DOWN && widget &&
-	    widget != wm->_list.window && !gnt_widget_get_transient(widget)) {
+	    !gnt_wm_is_list_window(wm, widget) &&
+	    !gnt_widget_get_transient(widget)) {
 		gint widgetx, widgety;
-		if (!gnt_ws_is_top_widget(wm->cws, widget)) {
+		if (!gnt_ws_is_top_widget(gnt_wm_get_current_workspace(wm),
+		                          widget)) {
 			gnt_wm_raise_window(wm, widget);
 		}
 		gnt_widget_get_position(widget, &widgetx, &widgety);
@@ -237,7 +241,8 @@
 	} else if (event == GNT_MOUSE_UP) {
 		if (button == MOUSE_NONE && y == getmaxy(stdscr) - 1) {
 			/* Clicked on the taskbar */
-			int n = g_list_length(gnt_ws_get_list(wm->cws));
+			int n = g_list_length(gnt_ws_get_list(
+			        gnt_wm_get_current_workspace(wm)));
 			if (n) {
 				int width = getmaxx(stdscr) / n;
 				gnt_bindable_perform_action_named(GNT_BINDABLE(wm), "switch-window-n", x/width, NULL);
@@ -298,8 +303,9 @@
 	gboolean is_special = FALSE;
 	gboolean is_escape = FALSE;
 
-	if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD)
+	if (gnt_wm_get_keypress_mode(wm) == GNT_KP_MODE_WAIT_ON_CHILD) {
 		return FALSE;
+	}
 
 	if (HOLDING_ESCAPE) {
 		is_escape = TRUE;
@@ -369,8 +375,9 @@
 	char *k;
 	char *cvrt = NULL;
 
-	if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD)
+	if (gnt_wm_get_keypress_mode(wm) == GNT_KP_MODE_WAIT_ON_CHILD) {
 		return FALSE;
+	}
 
 	rd = read(STDIN_FILENO, keys + HOLDING_ESCAPE, sizeof(keys) - 1 - HOLDING_ESCAPE);
 	if (rd < 0)
@@ -500,15 +507,15 @@
 ask_before_exit(void)
 {
 	static GntWidget *win = NULL;
+	GntMenu *menu;
 	GntWidget *bbox, *button;
 
-	if (wm->menu) {
-		do {
-			gnt_widget_hide(GNT_WIDGET(wm->menu));
-			if (wm->menu)
-				wm->menu = gnt_menu_get_parent_menu(wm->menu);
-		} while (wm->menu);
+	menu = gnt_wm_get_menu(wm);
+	while (menu) {
+		gnt_widget_hide(GNT_WIDGET(menu));
+		menu = gnt_menu_get_parent_menu(menu);
 	}
+	gnt_wm_set_menu(wm, NULL);
 
 	if (win)
 		goto raise;
@@ -694,8 +701,9 @@
 
 void gnt_main()
 {
-	wm->loop = g_main_loop_new(NULL, FALSE);
-	g_main_loop_run(wm->loop);
+	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
+	gnt_wm_set_mainloop(wm, loop);
+	g_main_loop_run(loop);
 }
 
 /*********************************
@@ -704,10 +712,11 @@
 
 void gnt_window_present(GntWidget *window)
 {
-	if (wm->event_stack)
+	if (gnt_wm_get_event_stack(wm)) {
 		gnt_wm_raise_window(wm, window);
-	else
+	} else {
 		gnt_widget_set_urgent(window);
+	}
 }
 
 void gnt_screen_occupy(GntWidget *widget)
@@ -739,9 +748,10 @@
 
 	widget = gnt_widget_get_toplevel(widget);
 
-	if (widget == wm->_list.window)
+	if (gnt_wm_is_list_window(wm, widget)) {
 		return TRUE;
-	if (gnt_ws_is_top_widget(wm->cws, widget)) {
+	}
+	if (gnt_ws_is_top_widget(gnt_wm_get_current_workspace(wm), widget)) {
 		if (GNT_IS_BOX(widget) &&
 		    (gnt_box_get_active(GNT_BOX(widget)) == w || widget == w)) {
 			return TRUE;
@@ -754,7 +764,7 @@
 {
 	widget = gnt_widget_get_toplevel(widget);
 
-	if (gnt_ws_is_top_widget(wm->cws, widget)) {
+	if (gnt_ws_is_top_widget(gnt_wm_get_current_workspace(wm), widget)) {
 		return;
 	}
 
@@ -812,29 +822,31 @@
 	action->label = g_strdup(label);
 	action->callback = callback;
 
-	wm->acts = g_list_append(wm->acts, action);
+	gnt_wm_add_action(wm, action);
 }
 
 static void
 reset_menu(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer data)
 {
-	wm->menu = NULL;
+	gnt_wm_set_menu(wm, NULL);
 }
 
 gboolean gnt_screen_menu_show(gpointer newmenu)
 {
-	if (wm->menu) {
+	if (gnt_wm_get_menu(wm)) {
 		/* For now, if a menu is being displayed, then another menu
 		 * can NOT take over. */
 		return FALSE;
 	}
 
-	wm->menu = newmenu;
-	gnt_widget_set_visible(GNT_WIDGET(wm->menu), TRUE);
-	gnt_widget_draw(GNT_WIDGET(wm->menu));
+	gnt_wm_set_menu(wm, GNT_MENU(newmenu));
+	gnt_widget_set_visible(GNT_WIDGET(newmenu), TRUE);
+	gnt_widget_draw(GNT_WIDGET(newmenu));
 
-	g_signal_connect(G_OBJECT(wm->menu), "hide", G_CALLBACK(reset_menu), NULL);
-	g_signal_connect(G_OBJECT(wm->menu), "destroy", G_CALLBACK(reset_menu), NULL);
+	g_signal_connect(G_OBJECT(newmenu), "hide", G_CALLBACK(reset_menu),
+	                 NULL);
+	g_signal_connect(G_OBJECT(newmenu), "destroy", G_CALLBACK(reset_menu),
+	                 NULL);
 
 	return TRUE;
 }
@@ -871,7 +883,7 @@
 #ifndef _WIN32
 	clean_pid();
 #endif
-	wm->mode = GNT_KP_MODE_NORMAL;
+	gnt_wm_set_keypress_mode(wm, GNT_KP_MODE_NORMAL);
 	endwin();
 	setup_io();
 	refresh();
@@ -895,7 +907,7 @@
 	cp->callback = callback;
 	cp->data = data;
 	g_source_remove(channel_read_callback);
-	wm->mode = GNT_KP_MODE_WAIT_ON_CHILD;
+	gnt_wm_set_keypress_mode(wm, GNT_KP_MODE_WAIT_ON_CHILD);
 	g_child_watch_add(pid, reap_child, cp);
 
 	return TRUE;
@@ -903,7 +915,8 @@
 
 gboolean gnt_is_refugee()
 {
-	return (wm && wm->mode == GNT_KP_MODE_WAIT_ON_CHILD);
+	return (wm &&
+	        gnt_wm_get_keypress_mode(wm) == GNT_KP_MODE_WAIT_ON_CHILD);
 }
 
 const char *C_(const char *x)
--- a/gntstyle.c	Fri May 10 23:13:35 2019 +0000
+++ b/gntstyle.c	Fri May 10 23:31:00 2019 +0000
@@ -28,6 +28,8 @@
 #include "gntcolors.h"
 #include "gntws.h"
 
+#include "gntwmprivate.h"
+
 #include <glib.h>
 #include <ctype.h>
 #include <stdlib.h>
@@ -188,15 +190,17 @@
 
 		titles = g_key_file_get_string_list(gkfile, group, "window-names", &c, NULL);
 		if (titles) {
-			for (j = 0; j < c; ++j)
-				g_hash_table_replace(wm->name_places, g_strdup(titles[j]), ws);
+			for (j = 0; j < c; ++j) {
+				gnt_wm_set_place_by_name(wm, titles[j], ws);
+			}
 			g_strfreev(titles);
 		}
 
 		titles = g_key_file_get_string_list(gkfile, group, "window-titles", &c, NULL);
 		if (titles) {
-			for (j = 0; j < c; ++j)
-				g_hash_table_replace(wm->title_places, g_strdup(titles[j]), ws);
+			for (j = 0; j < c; ++j) {
+				gnt_wm_set_place_by_title(wm, titles[j], ws);
+			}
 			g_strfreev(titles);
 		}
 	}
--- a/gntwm.c	Fri May 10 23:13:35 2019 +0000
+++ b/gntwm.c	Fri May 10 23:31:00 2019 +0000
@@ -63,17 +63,51 @@
 #include "gntboxprivate.h"
 #include "gntmenuprivate.h"
 #include "gntwidgetprivate.h"
+#include "gntwmprivate.h"
 #include "gntwsprivate.h"
 
 #define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
 
+typedef struct _GntListWindow
+{
+	GntWidget *window;
+	GntWidget *tree;
+} GntListWindow;
+
 typedef struct
 {
+	GMainLoop *loop;
+
 	GList *workspaces;
 	GList *tagged; /* tagged windows */
-
+	GntWS *cws;
+
+	GntListWindow list;
 	GntListWindow *windows; /* Window-list window */
 	GntListWindow *actions; /* Action-list window */
+
+	GHashTable *nodes;        /* GntWidget -> GntNode */
+	GHashTable *name_places;  /* window name -> ws */
+	GHashTable *title_places; /* window title -> ws */
+
+	GList *acts; /* List of actions */
+
+	/* Currently active menu. There can be at most one menu at a time on
+	 * the screen. If there is a menu being displayed, then all the
+	 * keystrokes will be sent to the menu until it is closed, either when
+	 * the user activates a menuitem, or presses Escape to cancel the menu.
+	 */
+	GntMenu *menu;
+
+	/* Will be set to %TRUE when a user-event, ie. a mouse-click or a
+	 * key-press is being processed. This variable will be used to
+	 * determine whether to give focus to a new window.
+	 */
+	gboolean event_stack;
+
+	GntKeyPressMode mode;
+
+	GHashTable *positions;
 } GntWMPrivate;
 
 enum
@@ -129,6 +163,7 @@
 	g_free(node);
 }
 
+/* Private. */
 void
 gnt_wm_copy_win(GntWidget *widget, GntNode *node)
 {
@@ -245,13 +280,16 @@
 static gboolean
 update_screen(GntWM *wm)
 {
-	if (wm->mode == GNT_KP_MODE_WAIT_ON_CHILD)
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->mode == GNT_KP_MODE_WAIT_ON_CHILD) {
 		return TRUE;
-
-	if (wm->menu) {
-		GntMenu *top = wm->menu;
+	}
+
+	if (priv->menu) {
+		GntMenu *top = priv->menu;
 		while (top) {
-			GntNode *node = g_hash_table_lookup(wm->nodes, top);
+			GntNode *node = g_hash_table_lookup(priv->nodes, top);
 			if (node)
 				top_panel(node->panel);
 			top = gnt_menu_get_submenu(top);
@@ -340,6 +378,7 @@
 static void
 read_window_positions(GntWM *wm)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GKeyFile *gfile = g_key_file_new();
 	char *filename = g_build_filename(gnt_get_config_dir(), ".gntpositions", NULL);
 	GError *error = NULL;
@@ -369,7 +408,7 @@
 				GntPosition *p = g_new0(GntPosition, 1);
 				p->x = x;
 				p->y = y;
-				g_hash_table_replace(wm->positions, g_strdup(title + 1), p);
+				g_hash_table_replace(priv->positions, g_strdup(title + 1), p);
 			} else {
 				gnt_warning("Invalid number of arguments (%" G_GSIZE_FORMAT
 						") for positioning a window.", l);
@@ -398,18 +437,20 @@
 {
 	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 
-	wm->name_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	wm->title_places = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	priv->name_places =
+	        g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	priv->title_places =
+	        g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 	gnt_style_read_workspaces(wm);
 	if (priv->workspaces == NULL) {
-		wm->cws = gnt_ws_new("default");
-		gnt_wm_add_workspace(wm, wm->cws);
+		priv->cws = gnt_ws_new("default");
+		gnt_wm_add_workspace(wm, priv->cws);
 	} else {
-		wm->cws = priv->workspaces->data;
+		priv->cws = priv->workspaces->data;
 	}
-	wm->event_stack = FALSE;
-	wm->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_node);
-	wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	priv->nodes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+	                                    free_node);
+	priv->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 	if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE))
 		read_window_positions(wm);
 	g_timeout_add_seconds(IDLE_CHECK_INTERVAL, check_idle, NULL);
@@ -420,23 +461,25 @@
 static void
 switch_window(GntWM *wm, int direction, gboolean urgent)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *w = NULL, *wid = NULL;
 	GList *list;
 	int pos, orgpos;
 
-	if (wm->_list.window || wm->menu)
+	if (priv->list.window || priv->menu) {
 		return;
-
-	if (gnt_ws_is_empty(wm->cws) || gnt_ws_is_single(wm->cws)) {
+	}
+
+	if (gnt_ws_is_empty(priv->cws) || gnt_ws_is_single(priv->cws)) {
 		return;
 	}
 
-	if (wm->mode != GNT_KP_MODE_NORMAL) {
+	if (priv->mode != GNT_KP_MODE_NORMAL) {
 		ensure_normal_mode(wm);
 	}
 
-	w = gnt_ws_get_top_widget(wm->cws);
-	list = gnt_ws_get_list(wm->cws);
+	w = gnt_ws_get_top_widget(priv->cws);
+	list = gnt_ws_get_list(priv->cws);
 	orgpos = pos = g_list_index(list, w);
 	g_return_if_fail(pos >= 0);
 
@@ -477,10 +520,11 @@
 switch_window_n(GntBindable *bind, GList *list)
 {
 	GntWM *wm = GNT_WM(bind);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GList *l;
 	int n;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return TRUE;
 	}
 
@@ -489,7 +533,7 @@
 	else
 		n = 0;
 
-	if ((l = g_list_nth(gnt_ws_get_list(wm->cws), n)) != NULL) {
+	if ((l = g_list_nth(gnt_ws_get_list(priv->cws), n)) != NULL) {
 		gnt_wm_raise_window(wm, l->data);
 	}
 
@@ -500,15 +544,16 @@
 window_scroll_up(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *window;
 	GntNode *node;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return TRUE;
 	}
 
-	window = gnt_ws_get_top_widget(wm->cws);
-	node = g_hash_table_lookup(wm->nodes, window);
+	window = gnt_ws_get_top_widget(priv->cws);
+	node = g_hash_table_lookup(priv->nodes, window);
 	if (!node)
 		return TRUE;
 
@@ -524,16 +569,17 @@
 window_scroll_down(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *window;
 	GntNode *node;
 	int w, h;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return TRUE;
 	}
 
-	window = gnt_ws_get_top_widget(wm->cws);
-	node = g_hash_table_lookup(wm->nodes, window);
+	window = gnt_ws_get_top_widget(priv->cws);
+	node = g_hash_table_lookup(priv->nodes, window);
 	if (!node)
 		return TRUE;
 
@@ -550,12 +596,14 @@
 window_close(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-
-	if (wm->_list.window)
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window) {
 		return TRUE;
-
-	if (!gnt_ws_is_empty(wm->cws)) {
-		gnt_widget_destroy(gnt_ws_get_top_widget(wm->cws));
+	}
+
+	if (!gnt_ws_is_empty(priv->cws)) {
+		gnt_widget_destroy(gnt_ws_get_top_widget(priv->cws));
 		ensure_normal_mode(wm);
 	}
 
@@ -566,8 +614,9 @@
 destroy__list(G_GNUC_UNUSED GntWidget *widget, GntWM *wm)
 {
 	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
-	wm->_list.window = NULL;
-	wm->_list.tree = NULL;
+
+	priv->list.window = NULL;
+	priv->list.tree = NULL;
 	priv->windows = NULL;
 	priv->actions = NULL;
 	update_screen(wm);
@@ -576,14 +625,15 @@
 static void
 setup__list(GntWM *wm)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *tree, *win;
 	ensure_normal_mode(wm);
-	win = wm->_list.window = gnt_box_new(FALSE, FALSE);
+	win = priv->list.window = gnt_box_new(FALSE, FALSE);
 	gnt_box_set_toplevel(GNT_BOX(win), TRUE);
 	gnt_box_set_pad(GNT_BOX(win), 0);
 	gnt_widget_set_transient(win, TRUE);
 
-	tree = wm->_list.tree = gnt_tree_new();
+	tree = priv->list.tree = gnt_tree_new();
 	gnt_box_add_widget(GNT_BOX(win), tree);
 
 	g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy__list), wm);
@@ -595,7 +645,7 @@
 	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(tree));
 
-	gnt_widget_destroy(wm->_list.window);
+	gnt_widget_destroy(priv->list.window);
 
 	if (!sel)
 		return;
@@ -615,7 +665,7 @@
 	GList *iter;
 	GntTree *tree = GNT_TREE(priv->windows->tree);
 	if (!workspace) {
-		for (iter = gnt_ws_get_list(wm->cws); iter; iter = iter->next) {
+		for (iter = gnt_ws_get_list(priv->cws); iter; iter = iter->next) {
 			GntBox *box = GNT_BOX(iter->data);
 
 			gnt_tree_add_row_last(
@@ -648,7 +698,9 @@
 static gboolean
 window_list_key_pressed(GntWidget *widget, const char *text, GntWM *wm)
 {
-	if (text[1] == 0 && !gnt_ws_is_empty(wm->cws)) {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (text[1] == 0 && !gnt_ws_is_empty(priv->cws)) {
 		GntBindable *sel = gnt_tree_get_selection_data(GNT_TREE(widget));
 		switch (text[0]) {
 			case '-':
@@ -682,7 +734,7 @@
 	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *tree, *win;
 	setup__list(wm);
-	priv->windows = &wm->_list;
+	priv->windows = &priv->list;
 
 	win = priv->windows->window;
 	tree = priv->windows->tree;
@@ -691,10 +743,10 @@
 
 	populate_window_list(wm, workspace);
 
-	if (!gnt_ws_is_empty(wm->cws)) {
-		gnt_tree_set_selected(GNT_TREE(tree), gnt_ws_get_top_widget(wm->cws));
+	if (!gnt_ws_is_empty(priv->cws)) {
+		gnt_tree_set_selected(GNT_TREE(tree), gnt_ws_get_top_widget(priv->cws));
 	} else if (workspace) {
-		gnt_tree_set_selected(GNT_TREE(tree), wm->cws);
+		gnt_tree_set_selected(GNT_TREE(tree), priv->cws);
 	}
 
 	g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(window_list_activate), wm);
@@ -712,11 +764,13 @@
 window_list(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-
-	if (wm->_list.window || wm->menu)
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window || priv->menu) {
 		return TRUE;
-
-	if (gnt_ws_is_empty(wm->cws)) {
+	}
+
+	if (gnt_ws_is_empty(priv->cws)) {
 		return TRUE;
 	}
 
@@ -894,7 +948,8 @@
 static void
 shift_window(GntWM *wm, GntWidget *widget, int dir)
 {
-	GList *all = gnt_ws_get_list(wm->cws);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+	GList *all = gnt_ws_get_list(priv->cws);
 	GList *list = g_list_find(all, widget);
 	int length, pos;
 	if (!list)
@@ -914,11 +969,11 @@
 
 	all = g_list_insert(all, widget, pos);
 	all = g_list_delete_link(all, list);
-	gnt_ws_set_list(wm->cws, all);
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
-	if (!gnt_ws_is_empty(wm->cws)) {
-		GntWidget *w = gnt_ws_get_top_widget(wm->cws);
-		GntNode *node = g_hash_table_lookup(wm->nodes, w);
+	gnt_ws_set_list(priv->cws, all);
+	gnt_ws_draw_taskbar(priv->cws, FALSE);
+	if (!gnt_ws_is_empty(priv->cws)) {
+		GntWidget *w = gnt_ws_get_top_widget(priv->cws);
+		GntNode *node = g_hash_table_lookup(priv->nodes, w);
 		top_panel(node->panel);
 		update_panels();
 		doupdate();
@@ -929,14 +984,17 @@
 shift_left(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-	if (wm->_list.window)
-		return TRUE;
-
-	if (gnt_ws_is_empty(wm->cws)) {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window) {
 		return TRUE;
 	}
 
-	shift_window(wm, gnt_ws_get_top_widget(wm->cws), -1);
+	if (gnt_ws_is_empty(priv->cws)) {
+		return TRUE;
+	}
+
+	shift_window(wm, gnt_ws_get_top_widget(priv->cws), -1);
 	return TRUE;
 }
 
@@ -944,24 +1002,27 @@
 shift_right(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-
-	if (wm->_list.window)
-		return TRUE;
-
-	if (gnt_ws_is_empty(wm->cws)) {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window) {
 		return TRUE;
 	}
 
-	shift_window(wm, gnt_ws_get_top_widget(wm->cws), 1);
+	if (gnt_ws_is_empty(priv->cws)) {
+		return TRUE;
+	}
+
+	shift_window(wm, gnt_ws_get_top_widget(priv->cws), 1);
 	return TRUE;
 }
 
 static void
 action_list_activate(GntTree *tree, GntWM *wm)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntAction *action = gnt_tree_get_selection_data(tree);
 	action->callback();
-	gnt_widget_destroy(wm->_list.window);
+	gnt_widget_destroy(priv->list.window);
 }
 
 static int
@@ -981,14 +1042,17 @@
 	GntWM *wm = GNT_WM(bindable);
 	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	int n;
-	if (wm->_list.window || wm->menu)
+
+	if (priv->list.window || priv->menu) {
 		return TRUE;
-
-	if (wm->acts == NULL)
+	}
+
+	if (priv->acts == NULL) {
 		return TRUE;
+	}
 
 	setup__list(wm);
-	priv->actions = &wm->_list;
+	priv->actions = &priv->list;
 
 	win = priv->actions->window;
 	tree = priv->actions->tree;
@@ -998,13 +1062,13 @@
 	/* XXX: Do we really want this? */
 	gnt_tree_set_compare_func(GNT_TREE(tree), compare_action);
 
-	for (iter = wm->acts; iter; iter = iter->next) {
+	for (iter = priv->acts; iter; iter = iter->next) {
 		GntAction *action = iter->data;
 		gnt_tree_add_row_last(GNT_TREE(tree), action,
 				gnt_tree_create_row(GNT_TREE(tree), action->label), NULL);
 	}
 	g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(action_list_activate), wm);
-	n = g_list_length(wm->acts);
+	n = g_list_length(priv->acts);
 	gnt_widget_set_size(tree, 0, n);
 	gnt_widget_set_position(win, 0, getmaxy(stdscr) - 3 - n);
 
@@ -1056,6 +1120,7 @@
 static void
 window_reverse(GntWidget *win, gboolean set, GntWM *wm)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	int i;
 	int w, h;
 	WINDOW *d;
@@ -1079,18 +1144,20 @@
 	for (i = 0; i < h; i += reverse_char(d, i, 0, set));
 	for (i = 0; i < h; i += reverse_char(d, i, w-1, set));
 
-	gnt_wm_copy_win(win, g_hash_table_lookup(wm->nodes, win));
+	gnt_wm_copy_win(win, g_hash_table_lookup(priv->nodes, win));
 	update_screen(wm);
 }
 
 static void
 ensure_normal_mode(GntWM *wm)
 {
-	if (wm->mode != GNT_KP_MODE_NORMAL) {
-		if (!gnt_ws_is_empty(wm->cws)) {
-			window_reverse(gnt_ws_get_top_widget(wm->cws), FALSE, wm);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->mode != GNT_KP_MODE_NORMAL) {
+		if (!gnt_ws_is_empty(priv->cws)) {
+			window_reverse(gnt_ws_get_top_widget(priv->cws), FALSE, wm);
 		}
-		wm->mode = GNT_KP_MODE_NORMAL;
+		priv->mode = GNT_KP_MODE_NORMAL;
 	}
 }
 
@@ -1098,14 +1165,17 @@
 start_move(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-	if (wm->_list.window || wm->menu)
-		return TRUE;
-	if (gnt_ws_is_empty(wm->cws)) {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window || priv->menu) {
 		return TRUE;
 	}
-
-	wm->mode = GNT_KP_MODE_MOVE;
-	window_reverse(gnt_ws_get_top_widget(wm->cws), TRUE, wm);
+	if (gnt_ws_is_empty(priv->cws)) {
+		return TRUE;
+	}
+
+	priv->mode = GNT_KP_MODE_MOVE;
+	window_reverse(gnt_ws_get_top_widget(priv->cws), TRUE, wm);
 
 	return TRUE;
 }
@@ -1114,14 +1184,17 @@
 start_resize(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-	if (wm->_list.window || wm->menu)
-		return TRUE;
-	if (gnt_ws_is_empty(wm->cws)) {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window || priv->menu) {
 		return TRUE;
 	}
-
-	wm->mode = GNT_KP_MODE_RESIZE;
-	window_reverse(gnt_ws_get_top_widget(wm->cws), TRUE, wm);
+	if (gnt_ws_is_empty(priv->cws)) {
+		return TRUE;
+	}
+
+	priv->mode = GNT_KP_MODE_RESIZE;
+	window_reverse(gnt_ws_get_top_widget(priv->cws), TRUE, wm);
 
 	return TRUE;
 }
@@ -1130,9 +1203,11 @@
 wm_quit(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
 	if (write_timeout)
 		write_already(wm);
-	g_main_loop_quit(wm->loop);
+	g_main_loop_quit(priv->loop);
 	return TRUE;
 }
 
@@ -1147,21 +1222,23 @@
 refresh_screen(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GList *iter;
 
 	endwin();
 	refresh();
 
-	g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, GINT_TO_POINTER(TRUE));
+	g_hash_table_foreach(priv->nodes, (GHFunc)refresh_node,
+	                     GINT_TO_POINTER(TRUE));
 	g_signal_emit(wm, signals[SIG_TERMINAL_REFRESH], 0);
 
-	for (iter = gnt_ws_get_last(wm->cws); iter; iter = iter->prev) {
+	for (iter = gnt_ws_get_last(priv->cws); iter; iter = iter->prev) {
 		GntWidget *w = iter->data;
-		GntNode *node = g_hash_table_lookup(wm->nodes, w);
+		GntNode *node = g_hash_table_lookup(priv->nodes, w);
 		top_panel(node->panel);
 	}
 
-	gnt_ws_draw_taskbar(wm->cws, TRUE);
+	gnt_ws_draw_taskbar(priv->cws, TRUE);
 	update_screen(wm);
 
 	curs_set(0);   /* endwin resets the cursor to normal */
@@ -1211,10 +1288,10 @@
 	GntWidget *widget;
 	GList *link;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return FALSE;
 	}
-	widget = gnt_ws_get_top_widget(wm->cws);
+	widget = gnt_ws_get_top_widget(priv->cws);
 
 	link = g_list_find(priv->tagged, widget);
 	if (link) {
@@ -1240,7 +1317,7 @@
 
 	for (iter = priv->tagged; iter; iter = g_list_delete_link(iter, iter)) {
 		GntWidget *widget = GNT_WIDGET(iter->data);
-		gnt_wm_widget_move_workspace(wm, wm->cws, widget);
+		gnt_wm_widget_move_workspace(wm, priv->cws, widget);
 		remove_tag(widget, wm);
 	}
 
@@ -1252,9 +1329,11 @@
 workspace_list(GntBindable *b, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(b);
-
-	if (wm->_list.window || wm->menu)
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (priv->list.window || priv->menu) {
 		return TRUE;
+	}
 
 	list_of_windows(wm, TRUE);
 
@@ -1276,8 +1355,10 @@
 ignore_keys_start(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
-
-	if(!wm->menu && !wm->_list.window && wm->mode == GNT_KP_MODE_NORMAL){
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+
+	if (!priv->menu && !priv->list.window &&
+	    priv->mode == GNT_KP_MODE_NORMAL) {
 		ignore_keys = TRUE;
 		return TRUE;
 	}
@@ -1380,13 +1461,14 @@
 help_for_window(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *widget;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return FALSE;
 	}
 
-	widget = gnt_ws_get_top_widget(wm->cws);
+	widget = gnt_ws_get_top_widget(priv->cws);
 
 	return help_for_bindable(wm,GNT_BINDABLE(widget));
 }
@@ -1395,13 +1477,14 @@
 help_for_widget(GntBindable *bindable, G_GNUC_UNUSED GList *params)
 {
 	GntWM *wm = GNT_WM(bindable);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWidget *widget;
 
-	if (gnt_ws_is_empty(wm->cws)) {
+	if (gnt_ws_is_empty(priv->cws)) {
 		return TRUE;
 	}
 
-	widget = gnt_ws_get_top_widget(wm->cws);
+	widget = gnt_ws_get_top_widget(priv->cws);
 	if (!GNT_IS_BOX(widget))
 		return TRUE;
 
@@ -1425,10 +1508,10 @@
 	GList *list;
 
 	list = NULL;
-	g_hash_table_foreach(wm->nodes, (GHFunc)accumulate_windows, &list);
+	g_hash_table_foreach(priv->nodes, (GHFunc)accumulate_windows, &list);
 	g_list_free_full(list, (GDestroyNotify)gnt_widget_destroy);
-	g_hash_table_destroy(wm->nodes);
-	wm->nodes = NULL;
+	g_hash_table_destroy(priv->nodes);
+	priv->nodes = NULL;
 
 	g_list_free_full(priv->workspaces, g_object_unref);
 	priv->workspaces = NULL;
@@ -1631,6 +1714,17 @@
 /******************************************************************************
  * GntWM API
  *****************************************************************************/
+GntWS *
+gnt_wm_get_current_workspace(GntWM *wm)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), NULL);
+
+	priv = gnt_wm_get_instance_private(wm);
+	return priv->cws;
+}
+
 void
 gnt_wm_add_workspace(GntWM *wm, GntWS *ws)
 {
@@ -1656,22 +1750,22 @@
 	if (!s)
 		return FALSE;
 
-	if (wm->_list.window) {
-		gnt_widget_destroy(wm->_list.window);
+	if (priv->list.window) {
+		gnt_widget_destroy(priv->list.window);
 	}
 	ensure_normal_mode(wm);
-	gnt_ws_hide(wm->cws, wm->nodes);
-	wm->cws = s;
-	gnt_ws_show(wm->cws, wm->nodes);
-
-	gnt_ws_draw_taskbar(wm->cws, TRUE);
+	gnt_ws_hide(priv->cws, priv->nodes);
+	priv->cws = s;
+	gnt_ws_show(priv->cws, priv->nodes);
+
+	gnt_ws_draw_taskbar(priv->cws, TRUE);
 	update_screen(wm);
-	if (!gnt_ws_is_empty(wm->cws)) {
-		gnt_wm_raise_window(wm, gnt_ws_get_top_widget(wm->cws));
+	if (!gnt_ws_is_empty(priv->cws)) {
+		gnt_wm_raise_window(wm, gnt_ws_get_top_widget(priv->cws));
 	}
 
-	if (act && g_list_find(act, wm->cws)) {
-		act = g_list_remove(act, wm->cws);
+	if (act && g_list_find(act, priv->cws)) {
+		act = g_list_remove(act, priv->cws);
 		update_act_msg();
 	}
 	return TRUE;
@@ -1686,7 +1780,7 @@
 	g_return_val_if_fail(GNT_IS_WM(wm), FALSE);
 	priv = gnt_wm_get_instance_private(wm);
 
-	n = g_list_index(priv->workspaces, wm->cws);
+	n = g_list_index(priv->workspaces, priv->cws);
 	return gnt_wm_switch_workspace(wm, --n);
 }
 
@@ -1699,7 +1793,7 @@
 	g_return_val_if_fail(GNT_IS_WM(wm), FALSE);
 	priv = gnt_wm_get_instance_private(wm);
 
-	n = g_list_index(priv->workspaces, wm->cws);
+	n = g_list_index(priv->workspaces, priv->cws);
 	return gnt_wm_switch_workspace(wm, ++n);
 }
 
@@ -1718,11 +1812,17 @@
 void
 gnt_wm_widget_move_workspace(GntWM *wm, GntWS *neww, GntWidget *widget)
 {
-	GntWS *oldw = gnt_wm_widget_find_workspace(wm, widget);
+	GntWMPrivate *priv = NULL;
+	GntWS *oldw = NULL;
 	GntNode *node;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	oldw = gnt_wm_widget_find_workspace(wm, widget);
 	if (!oldw || oldw == neww)
 		return;
-	node = g_hash_table_lookup(wm->nodes, widget);
+	node = g_hash_table_lookup(priv->nodes, widget);
 	if (node && node->ws == neww)
 		return;
 
@@ -1731,10 +1831,10 @@
 
 	gnt_ws_remove_widget(oldw, widget);
 	gnt_ws_add_widget(neww, widget);
-	if (neww == wm->cws) {
-		gnt_ws_widget_show(widget, wm->nodes);
+	if (neww == priv->cws) {
+		gnt_ws_widget_show(widget, priv->nodes);
 	} else {
-		gnt_ws_widget_hide(widget, wm->nodes);
+		gnt_ws_widget_hide(widget, priv->nodes);
 	}
 }
 
@@ -1783,7 +1883,7 @@
 		return;
 	}
 
-	if (gnt_ws_is_top_widget(wm->cws, wid)) {
+	if (gnt_ws_is_top_widget(priv->cws, wid)) {
 		flag |= GNT_TEXT_FLAG_DIM;
 	} else if (gnt_widget_get_is_urgent(wid)) {
 		flag |= GNT_TEXT_FLAG_BOLD;
@@ -1803,26 +1903,28 @@
 static GntWS *
 new_widget_find_workspace(GntWM *wm, GntWidget *widget)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntWS *ret = NULL;
 	const gchar *name, *title;
 	title = gnt_box_get_title(GNT_BOX(widget));
 	if (title) {
-		ret = g_hash_table_find(wm->title_places, (GHRFunc)match_title,
-		                        (gpointer)title);
+		ret = g_hash_table_find(priv->title_places,
+		                        (GHRFunc)match_title, (gpointer)title);
 	}
 	if (ret)
 		return ret;
 	name = gnt_widget_get_name(widget);
 	if (name) {
-		ret = g_hash_table_find(wm->name_places, (GHRFunc)match_title,
+		ret = g_hash_table_find(priv->name_places, (GHRFunc)match_title,
 		                        (gpointer)name);
 	}
-	return ret ? ret : wm->cws;
+	return ret ? ret : priv->cws;
 }
 
 static void
 gnt_wm_new_window_real(GntWM *wm, GntWidget *widget)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	GntNode *node;
 	gboolean transient = FALSE;
 
@@ -1834,7 +1936,7 @@
 	node->me = widget;
 	node->scroll = 0;
 
-	g_hash_table_replace(wm->nodes, widget, node);
+	g_hash_table_replace(priv->nodes, widget, node);
 
 	refresh_node(widget, node, GINT_TO_POINTER(TRUE));
 
@@ -1870,8 +1972,8 @@
 	set_panel_userptr(node->panel, node);
 
 	if (!transient) {
-		GntWS *ws = wm->cws;
-		if (node->me != wm->_list.window) {
+		GntWS *ws = priv->cws;
+		if (!gnt_wm_is_list_window(wm, node->me)) {
 			if (GNT_IS_BOX(widget)) {
 				ws = new_widget_find_workspace(wm, widget);
 			}
@@ -1879,15 +1981,16 @@
 			gnt_ws_append_widget(ws, widget);
 		}
 
-		if (wm->event_stack || node->me == wm->_list.window ||
-				gnt_ws_is_top_widget(ws, node->me)) {
+		if (priv->event_stack || gnt_wm_is_list_window(wm, node->me) ||
+		    gnt_ws_is_top_widget(ws, node->me)) {
 			gnt_wm_raise_window(wm, node->me);
 		} else {
 			bottom_panel(node->panel);     /* New windows should not grab focus */
 			gnt_widget_set_focus(node->me, FALSE);
 			gnt_widget_set_urgent(node->me);
-			if (wm->cws != ws)
-				gnt_ws_widget_hide(widget, wm->nodes);
+			if (priv->cws != ws) {
+				gnt_ws_widget_hide(widget, priv->nodes);
+			}
 		}
 	}
 }
@@ -1902,7 +2005,7 @@
 	widget = gnt_widget_get_toplevel(widget);
 
 	if (!gnt_widget_get_visible(widget) ||
-	    g_hash_table_lookup(wm->nodes, widget)) {
+	    g_hash_table_lookup(priv->nodes, widget)) {
 		update_screen(wm);
 		return;
 	}
@@ -1910,7 +2013,7 @@
 	if (GNT_IS_BOX(widget)) {
 		const gchar *title = gnt_box_get_title(GNT_BOX(widget));
 		GntPosition *p = NULL;
-		if (title && (p = g_hash_table_lookup(wm->positions, title)) != NULL) {
+		if (title && (p = g_hash_table_lookup(priv->positions, title)) != NULL) {
 			sanitize_position(widget, &p->x, &p->y, TRUE);
 			gnt_widget_set_position(widget, p->x, p->y);
 			mvwin(gnt_widget_get_window(widget), p->y, p->x);
@@ -1923,7 +2026,7 @@
 	if (priv->windows && !gnt_widget_get_transient(widget)) {
 		if ((GNT_IS_BOX(widget) &&
 		     gnt_box_get_title(GNT_BOX(widget))) &&
-		    wm->_list.window != widget &&
+		    !gnt_wm_is_list_window(wm, widget) &&
 		    gnt_widget_get_take_focus(widget)) {
 			gnt_tree_add_row_last(
 			        GNT_TREE(priv->windows->tree), widget,
@@ -1932,13 +2035,13 @@
 			                gnt_box_get_title(GNT_BOX(widget))),
 			        g_object_get_data(G_OBJECT(priv->windows->tree),
 			                          "workspace")
-			                ? wm->cws
+			                ? priv->cws
 			                : NULL);
 			update_window_in_list(wm, widget);
 		}
 	}
 
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
+	gnt_ws_draw_taskbar(priv->cws, FALSE);
 	update_screen(wm);
 }
 
@@ -1961,11 +2064,11 @@
 
 	s = gnt_wm_widget_find_workspace(wm, widget);
 
-	if (g_hash_table_lookup(wm->nodes, widget) == NULL)
+	if (g_hash_table_lookup(priv->nodes, widget) == NULL)
 		return;
 
 	g_signal_emit(wm, signals[SIG_CLOSE_WIN], 0, widget);
-	g_hash_table_remove(wm->nodes, widget);
+	g_hash_table_remove(priv->nodes, widget);
 
 	if (priv->windows) {
 		gnt_tree_remove(GNT_TREE(priv->windows->tree), widget);
@@ -1977,15 +2080,15 @@
 		if (pos != -1) {
 			gnt_ws_remove_widget(s, widget);
 
-			if (!gnt_ws_is_empty(s) && wm->cws == s) {
+			if (!gnt_ws_is_empty(s) && priv->cws == s) {
 				gnt_wm_raise_window(wm, gnt_ws_get_top_widget(s));
 			}
 		}
-	} else if (transient && wm->cws && !gnt_ws_is_empty(wm->cws)) {
-		gnt_wm_update_window(wm, gnt_ws_get_top_widget(wm->cws));
+	} else if (transient && priv->cws && !gnt_ws_is_empty(priv->cws)) {
+		gnt_wm_update_window(wm, gnt_ws_get_top_widget(priv->cws));
 	}
 
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
+	gnt_ws_draw_taskbar(priv->cws, FALSE);
 	update_screen(wm);
 }
 
@@ -1996,6 +2099,7 @@
 
 gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
 {
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	gboolean ret = FALSE;
 
 	keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys);
@@ -2007,10 +2111,10 @@
 				return TRUE;
 			}
 		}
-		if (gnt_ws_is_empty(wm->cws)) {
+		if (gnt_ws_is_empty(priv->cws)) {
 			return FALSE;
 		}
-		return gnt_widget_key_pressed(gnt_ws_get_top_widget(wm->cws), keys);
+		return gnt_widget_key_pressed(gnt_ws_get_top_widget(priv->cws), keys);
 	}
 
 	if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys)) {
@@ -2018,10 +2122,10 @@
 	}
 
 	/* Do some manual checking */
-	if (!gnt_ws_is_empty(wm->cws) && wm->mode != GNT_KP_MODE_NORMAL) {
+	if (!gnt_ws_is_empty(priv->cws) && priv->mode != GNT_KP_MODE_NORMAL) {
 		int xmin = 0, ymin = 0, xmax = getmaxx(stdscr), ymax = getmaxy(stdscr) - 1;
 		int x, y, w, h;
-		GntWidget *widget = gnt_ws_get_top_widget(wm->cws);
+		GntWidget *widget = gnt_ws_get_top_widget(priv->cws);
 		int ox, oy, ow, oh;
 
 		gnt_widget_get_position(widget, &x, &y);
@@ -2029,7 +2133,7 @@
 		ox = x;	oy = y;
 		ow = w;	oh = h;
 
-		if (wm->mode == GNT_KP_MODE_MOVE) {
+		if (priv->mode == GNT_KP_MODE_MOVE) {
 			if (strcmp(keys, GNT_KEY_LEFT) == 0) {
 				if (x > xmin)
 					x--;
@@ -2048,7 +2152,7 @@
 				window_reverse(widget, TRUE, wm);
 				return TRUE;
 			}
-		} else if (wm->mode == GNT_KP_MODE_RESIZE) {
+		} else if (priv->mode == GNT_KP_MODE_RESIZE) {
 			if (strcmp(keys, GNT_KEY_LEFT) == 0) {
 				w--;
 			} else if (strcmp(keys, GNT_KEY_RIGHT) == 0) {
@@ -2068,15 +2172,15 @@
 		}
 		if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) {
 			window_reverse(widget, FALSE, wm);
-			wm->mode = GNT_KP_MODE_NORMAL;
+			priv->mode = GNT_KP_MODE_NORMAL;
 		}
 		return TRUE;
 	}
 
 	/* Escape to close the window-list or action-list window */
 	if (strcmp(keys, "\033") == 0) {
-		if (wm->_list.window) {
-			gnt_widget_destroy(wm->_list.window);
+		if (priv->list.window) {
+			gnt_widget_destroy(priv->list.window);
 			return TRUE;
 		}
 	} else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') {
@@ -2093,12 +2197,12 @@
 		return TRUE;
 	}
 
-	if (wm->menu)
-		ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
-	else if (wm->_list.window)
-		ret = gnt_widget_key_pressed(wm->_list.window, keys);
-	else if (!gnt_ws_is_empty(wm->cws)) {
-		GntWidget *win = gnt_ws_get_top_widget(wm->cws);
+	if (priv->menu) {
+		ret = gnt_widget_key_pressed(GNT_WIDGET(priv->menu), keys);
+	} else if (priv->list.window) {
+		ret = gnt_widget_key_pressed(priv->list.window, keys);
+	} else if (!gnt_ws_is_empty(priv->cws)) {
+		GntWidget *win = gnt_ws_get_top_widget(priv->cws);
 		if (GNT_IS_WINDOW(win)) {
 			GntMenu *menu = gnt_window_get_menu(GNT_WINDOW(win));
 			if (menu) {
@@ -2130,12 +2234,16 @@
 
 void gnt_wm_resize_window(GntWM *wm, GntWidget *widget, int width, int height)
 {
+	GntWMPrivate *priv = NULL;
 	gboolean ret = TRUE;
 	GntNode *node;
 	int maxx, maxy;
 
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
 	widget = gnt_widget_get_toplevel(widget);
-	node = g_hash_table_lookup(wm->nodes, widget);
+	node = g_hash_table_lookup(priv->nodes, widget);
 	if (!node)
 		return;
 
@@ -2169,6 +2277,7 @@
 write_already(gpointer data)
 {
 	GntWM *wm = data;
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
 	FILE *file;
 	char *filename;
 
@@ -2179,7 +2288,7 @@
 		gnt_warning("error opening file (%s) to save positions", filename);
 	} else {
 		fprintf(file, "[positions]\n");
-		g_hash_table_foreach(wm->positions, (GHFunc)write_gdi, file);
+		g_hash_table_foreach(priv->positions, (GHFunc)write_gdi, file);
 		fclose(file);
 	}
 
@@ -2200,11 +2309,15 @@
 
 void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y)
 {
+	GntWMPrivate *priv = NULL;
 	gboolean ret = TRUE;
 	GntNode *node;
 
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
 	widget = gnt_widget_get_toplevel(widget);
-	node = g_hash_table_lookup(wm->nodes, widget);
+	node = g_hash_table_lookup(priv->nodes, widget);
 	if (!node)
 		return;
 
@@ -2223,7 +2336,7 @@
 			GntPosition *p = g_new0(GntPosition, 1);
 			GntWidget *wid = node->me;
 			gnt_widget_get_position(wid, &p->x, &p->y);
-			g_hash_table_replace(wm->positions, g_strdup(title), p);
+			g_hash_table_replace(priv->positions, g_strdup(title), p);
 			write_positions_to_file(wm);
 		}
 	}
@@ -2234,32 +2347,38 @@
 static void
 gnt_wm_give_focus(GntWM *wm, GntWidget *widget)
 {
-	GntNode *node = g_hash_table_lookup(wm->nodes, widget);
+	GntWMPrivate *priv = gnt_wm_get_instance_private(wm);
+	GntNode *node = g_hash_table_lookup(priv->nodes, widget);
 
 	if (!node)
 		return;
 
 	gnt_widget_set_is_urgent(widget, FALSE);
-	if (widget != wm->_list.window && !GNT_IS_MENU(widget)) {
-		gnt_ws_bring_to_front(wm->cws, widget);
+	if (!gnt_wm_is_list_window(wm, widget) && !GNT_IS_MENU(widget)) {
+		gnt_ws_bring_to_front(priv->cws, widget);
 	}
 
 	gnt_widget_draw(widget);
 	top_panel(node->panel);
 
-	if (wm->_list.window) {
-		GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window);
+	if (priv->list.window) {
+		GntNode *nd =
+		        g_hash_table_lookup(priv->nodes, priv->list.window);
 		top_panel(nd->panel);
 	}
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
+	gnt_ws_draw_taskbar(priv->cws, FALSE);
 	update_screen(wm);
 }
 
 void gnt_wm_update_window(GntWM *wm, GntWidget *widget)
 {
+	GntWMPrivate *priv = NULL;
 	GntNode *node = NULL;
 	GntWS *ws;
 
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
 	widget = gnt_widget_get_toplevel(widget);
 	if (!GNT_IS_MENU(widget)) {
 		if (!GNT_IS_BOX(widget))
@@ -2268,17 +2387,17 @@
 	}
 
 	ws = gnt_wm_widget_find_workspace(wm, widget);
-	node = g_hash_table_lookup(wm->nodes, widget);
+	node = g_hash_table_lookup(priv->nodes, widget);
 	if (node == NULL) {
 		gnt_wm_new_window(wm, widget);
 	} else
 		g_signal_emit(wm, signals[SIG_UPDATE_WIN], 0, node);
 
-	if (ws == wm->cws || gnt_widget_get_transient(widget)) {
+	if (ws == priv->cws || gnt_widget_get_transient(widget)) {
 		gnt_wm_copy_win(widget, node);
-		gnt_ws_draw_taskbar(wm->cws, FALSE);
+		gnt_ws_draw_taskbar(priv->cws, FALSE);
 		update_screen(wm);
-	} else if (ws && ws != wm->cws && gnt_widget_get_is_urgent(widget)) {
+	} else if (ws && ws != priv->cws && gnt_widget_get_is_urgent(widget)) {
 		if (!act || (act && !g_list_find(act, ws)))
 			act = g_list_prepend(act, ws);
 		update_act_msg();
@@ -2303,18 +2422,166 @@
 
 	ws = gnt_wm_widget_find_workspace(wm, widget);
 
-	if (wm->cws != ws)
+	if (priv->cws != ws) {
 		gnt_wm_switch_workspace(wm, g_list_index(priv->workspaces, ws));
-
-	g_return_if_fail(wm->cws != NULL);
-
-	gnt_ws_bring_to_front(wm->cws, widget);
+	}
+
+	g_return_if_fail(priv->cws != NULL);
+
+	gnt_ws_bring_to_front(priv->cws, widget);
 	g_signal_emit(wm, signals[SIG_GIVE_FOCUS], 0, widget);
 }
 
-void gnt_wm_set_event_stack(GntWM *wm, gboolean set)
+void
+gnt_wm_foreach(GntWM *wm, GHFunc func, gpointer user_data)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	g_hash_table_foreach(priv->nodes, func, user_data);
+}
+
+gboolean
+gnt_wm_has_window_position(GntWM *wm, const gchar *title)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), FALSE);
+	priv = gnt_wm_get_instance_private(wm);
+
+	return g_hash_table_lookup(priv->positions, title) != NULL;
+}
+
+/* Private. */
+void
+gnt_wm_set_mainloop(GntWM *wm, GMainLoop *loop)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	priv->loop = loop;
+}
+
+/* Private. */
+gboolean
+gnt_wm_is_list_window(GntWM *wm, GntWidget *widget)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), FALSE);
+	priv = gnt_wm_get_instance_private(wm);
+
+	return priv->list.window == widget;
+}
+
+/* Private. */
+void
+gnt_wm_set_place_by_name(GntWM *wm, const gchar *name, GntWS *ws)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	g_hash_table_replace(priv->name_places, g_strdup(name), ws);
+}
+
+/* Private. */
+void
+gnt_wm_set_place_by_title(GntWM *wm, const gchar *title, GntWS *ws)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	g_hash_table_replace(priv->title_places, g_strdup(title), ws);
+}
+
+/* Private. */
+void
+gnt_wm_add_action(GntWM *wm, GntAction *action)
 {
-	wm->event_stack = set;
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	priv->acts = g_list_append(priv->acts, action);
+}
+
+/* Private. */
+GntMenu *
+gnt_wm_get_menu(GntWM *wm)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), NULL);
+	priv = gnt_wm_get_instance_private(wm);
+
+	return priv->menu;
+}
+
+/* Private. */
+void
+gnt_wm_set_menu(GntWM *wm, GntMenu *menu)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	priv->menu = menu;
 }
 
-
+/* Private. */
+gboolean
+gnt_wm_get_event_stack(GntWM *wm)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), FALSE);
+	priv = gnt_wm_get_instance_private(wm);
+
+	return priv->event_stack;
+}
+
+/* Private. */
+void
+gnt_wm_set_event_stack(GntWM *wm, gboolean set)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	priv->event_stack = set;
+}
+
+/* Private. */
+GntKeyPressMode
+gnt_wm_get_keypress_mode(GntWM *wm)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_val_if_fail(GNT_IS_WM(wm), GNT_KP_MODE_NORMAL);
+	priv = gnt_wm_get_instance_private(wm);
+
+	return priv->mode;
+}
+
+/* Private. */
+void
+gnt_wm_set_keypress_mode(GntWM *wm, GntKeyPressMode mode)
+{
+	GntWMPrivate *priv = NULL;
+
+	g_return_if_fail(GNT_IS_WM(wm));
+	priv = gnt_wm_get_instance_private(wm);
+
+	priv->mode = mode;
+}
--- a/gntwm.h	Fri May 10 23:13:35 2019 +0000
+++ b/gntwm.h	Fri May 10 23:31:00 2019 +0000
@@ -44,14 +44,6 @@
 #define GNT_IS_WM_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), GNT_TYPE_WM))
 #define GNT_WM_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), GNT_TYPE_WM, GntWMClass))
 
-typedef enum
-{
-	GNT_KP_MODE_NORMAL,
-	GNT_KP_MODE_RESIZE,
-	GNT_KP_MODE_MOVE,
-	GNT_KP_MODE_WAIT_ON_CHILD
-} GntKeyPressMode;
-
 typedef struct _GntNode GntNode;
 
 struct _GntNode
@@ -83,21 +75,8 @@
 	void (*callback)(void);
 } GntAction;
 
-typedef struct _GntListWindow {
-		GntWidget *window;
-		GntWidget *tree;
-} GntListWindow;
-
 /**
  * GntWM:
- * @acts: List of actions
- * @menu: Currently active menu. There can be at most one menu at a time on the
- *        screen. If there is a menu being displayed, then all the keystrokes
- *        will be sent to the menu until it is closed, either when the user
- *        activates a menuitem, or presses Escape to cancel the menu.
- * @event_stack: Will be set to %TRUE when a user-event, ie. a mouse-click or a
- *               key-press is being processed. This variable will be used to
- *               determine whether to give focus to a new window.
  *
  * Access to any fields is deprecated. See inline comments for replacements.
  *
@@ -106,27 +85,6 @@
 {
 	GntBindable inherit;
 
-	/*< public >*/
-	GMainLoop *GNTSEAL(loop);
-
-	GntWS *GNTSEAL(cws);
-
-	GntListWindow GNTSEAL(_list);
-
-	GHashTable *GNTSEAL(nodes);    /* GntWidget -> GntNode */
-	GHashTable *GNTSEAL(name_places);    /* window name -> ws*/
-	GHashTable *GNTSEAL(title_places);    /* window title -> ws */
-
-	GList *GNTSEAL(acts);
-
-	GntMenu *GNTSEAL(menu);
-
-	gboolean GNTSEAL(event_stack);
-
-	GntKeyPressMode GNTSEAL(mode);
-
-	GHashTable *GNTSEAL(positions);
-
 	/*< private >*/
 	void *res1;
 	void *res2;
@@ -201,6 +159,18 @@
 GType gnt_wm_get_type(void);
 
 /**
+ * gnt_wm_get_current_workspace:
+ * @wm: The window-manager.
+ *
+ * Gets the current workspace.
+ *
+ * Returns: (transfer none): The @GntWS that is currently active.
+ *
+ * Since: 3.0.0
+ */
+GntWS *gnt_wm_get_current_workspace(GntWM *wm);
+
+/**
  * gnt_wm_add_workspace:
  * @wm:   The window-manager.
  * @ws:   The workspace to add.
@@ -294,6 +264,21 @@
 void gnt_wm_window_close(GntWM *wm, GntWidget *widget);
 
 /**
+ * gnt_wm_foreach:
+ * @wm:                 The window-manager.
+ * @func: (scope call): The function to call for each key/value pair.
+ * @user_data:          User data to pass to the function.
+ *
+ * Calls the given function for each of the #GntWidget / #GntNode pairs in the
+ * #GntWM. The function is passed the widget and node of each pair, and the
+ * given @user_data parameter. The window manager may not be modified while
+ * iterating over it (you can't add/remove widgets).
+ *
+ * Since: 3.0.0
+ */
+void gnt_wm_foreach(GntWM *wm, GHFunc func, gpointer user_data);
+
+/**
  * gnt_wm_process_input:
  * @wm:      The window-manager.
  * @string:  The input string to process.
@@ -359,26 +344,26 @@
 void gnt_wm_raise_window(GntWM *wm, GntWidget *widget);
 
 /**
- * gnt_wm_set_event_stack:
- *
- * Internal function -- do not use.
- */
-void gnt_wm_set_event_stack(GntWM *wm, gboolean set);
-
-/**
- * gnt_wm_copy_win:
- *
- * Internal function -- do not use.
- */
-void gnt_wm_copy_win(GntWidget *widget, GntNode *node);
-
-/**
  * gnt_wm_get_idle_time:
  *
  * Returns:  The idle time of the user.
  */
 time_t gnt_wm_get_idle_time(void);
 
+/**
+ * gnt_wm_has_window_position:
+ * @wm:    The window-manager.
+ * @title: The title of the window.
+ *
+ * Checks whether the window manager has a recorded window position for a
+ * window with the given @title.
+ *
+ * Returns: #TRUE if a position is recorded for the window, %FALSE otherwise.
+ *
+ * Since: 3.0.0
+ */
+gboolean gnt_wm_has_window_position(GntWM *wm, const gchar *title);
+
 G_END_DECLS
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gntwmprivate.h	Fri May 10 23:31:00 2019 +0000
@@ -0,0 +1,71 @@
+/*
+ * GNT - The GLib Ncurses Toolkit
+ *
+ * GNT is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef GNT_WM_PRIVATE_H
+#define GNT_WM_PRIVATE_H
+
+#include "gnt.h"
+#include "gntwm.h"
+
+typedef enum
+{
+	GNT_KP_MODE_NORMAL,
+	GNT_KP_MODE_RESIZE,
+	GNT_KP_MODE_MOVE,
+	GNT_KP_MODE_WAIT_ON_CHILD
+} GntKeyPressMode;
+
+G_BEGIN_DECLS
+/* Private access to some internals. Contact us if you need these. */
+
+void gnt_wm_copy_win(GntWidget *widget, GntNode *node);
+
+void gnt_wm_set_mainloop(GntWM *wm, GMainLoop *loop);
+
+/*
+ * gnt_wm_is_list_window:
+ * @wm:     The window-manager.
+ * @widget: The widget to check.
+ *
+ * Check whether @widget is the window manager's listing window.
+ *
+ * Internal.
+ */
+gboolean gnt_wm_is_list_window(GntWM *wm, GntWidget *widget);
+
+void gnt_wm_set_place_by_name(GntWM *wm, const gchar *name, GntWS *ws);
+void gnt_wm_set_place_by_title(GntWM *wm, const gchar *title, GntWS *ws);
+
+void gnt_wm_add_action(GntWM *wm, GntAction *action);
+
+GntMenu *gnt_wm_get_menu(GntWM *wm);
+void gnt_wm_set_menu(GntWM *wm, GntMenu *menu);
+
+gboolean gnt_wm_get_event_stack(GntWM *wm);
+void gnt_wm_set_event_stack(GntWM *wm, gboolean set);
+
+GntKeyPressMode gnt_wm_get_keypress_mode(GntWM *wm);
+void gnt_wm_set_keypress_mode(GntWM *wm, GntKeyPressMode mode);
+
+G_END_DECLS
+
+#endif /* GNT_WM_PRIVATE_H */
--- a/gntws.c	Fri May 10 23:13:35 2019 +0000
+++ b/gntws.c	Fri May 10 23:31:00 2019 +0000
@@ -29,6 +29,8 @@
 #include "gntwm.h"
 #include "gntws.h"
 
+#include "gntwmprivate.h"
+
 typedef struct
 {
 	gchar *name;
--- a/wms/irssi.c	Fri May 10 23:13:35 2019 +0000
+++ b/wms/irssi.c	Fri May 10 23:31:00 2019 +0000
@@ -245,7 +245,9 @@
 		return;
 	g_object_set_data(
 	        G_OBJECT(win), "irssi-index",
-	        GINT_TO_POINTER(g_list_index(gnt_ws_get_list(wm->cws), win)));
+	        GINT_TO_POINTER(g_list_index(
+	                gnt_ws_get_list(gnt_wm_get_current_workspace(wm)),
+	                win)));
 	g_timeout_add(0, (GSourceFunc)update_conv_window_title, node);
 }
 
@@ -270,12 +272,14 @@
 {
 	GntWM *wm = GNT_WM(bindable);
 	GntIrssiWM *irssi = GNT_IRSSI_WM(wm);
+	GntWS *ws = NULL;
 	int vert, hor;
 	int x, y, w, h;
 	GntWidget *win;
 
-	if (gnt_ws_is_empty(wm->cws) ||
-	    is_buddylist(win = gnt_ws_get_top_widget(wm->cws))) {
+	ws = gnt_wm_get_current_workspace(wm);
+	if (gnt_ws_is_empty(ws) ||
+	    is_buddylist(win = gnt_ws_get_top_widget(ws))) {
 		return FALSE;
 	}
 
@@ -348,7 +352,7 @@
 {
 	GntIrssiWM *irssi = GNT_IRSSI_WM(wm);
 	draw_line_separators(irssi);
-	g_hash_table_foreach(wm->nodes, (GHFunc)refresh_window, wm);
+	gnt_wm_foreach(wm, (GHFunc)refresh_window, wm);
 }
 
 static void
--- a/wms/s.c	Fri May 10 23:13:35 2019 +0000
+++ b/wms/s.c	Fri May 10 23:31:00 2019 +0000
@@ -129,7 +129,7 @@
 			gnt_widget_set_size(win, -1, h + 2);  /* XXX: Why is the +2 needed here? -- sadrul */
 		} else if (!gnt_widget_get_transient(win)) {
 			const gchar *title = gnt_box_get_title(GNT_BOX(win));
-			if (title == NULL || !g_hash_table_lookup(wm->positions, title)) {
+			if (title == NULL || !gnt_wm_has_window_position(wm, title)) {
 				/* In the middle of the screen */
 				x = (maxx - w) / 2;
 				y = (maxy - h) / 2;
@@ -148,7 +148,7 @@
 static GntWidget *
 find_widget(GntWM *wm, const char *wname)
 {
-	GList *iter = gnt_ws_get_list(wm->cws);
+	GList *iter = gnt_ws_get_list(gnt_wm_get_current_workspace(wm));
 	for (; iter; iter = iter->next) {
 		GntWidget *widget = iter->data;
 		const char *name = gnt_widget_get_name(widget);