summaryrefslogtreecommitdiff
path: root/src/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/context.c')
-rw-r--r--src/context.c222
1 files changed, 148 insertions, 74 deletions
diff --git a/src/context.c b/src/context.c
index 32d7b3f..255480c 100644
--- a/src/context.c
+++ b/src/context.c
@@ -15,89 +15,163 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- /* desktop/shelf context handling */
+ /* contexts (this is derived from desktops) */
+#include <assert.h>
#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "list.h"
#include "context.h"
#include "desktop.h"
#include "vwm.h"
#include "xwindow.h"
-#include "window.h"
-/* switch to the desired context if it isn't already the focused one, inform caller if anything happened */
-int vwm_context_focus(vwm_t *vwm, vwm_context_t desired_context)
+/* make the specified context the most recently used one */
+vwm_context_t * vwm_context_mru(vwm_t *vwm, vwm_context_t *context)
{
- vwm_context_t entry_context = vwm->focused_context;
-
- switch (vwm->focused_context) {
- vwm_xwindow_t *xwin;
- vwm_window_t *vwin;
-
- case VWM_CONTEXT_SHELF:
- if (desired_context == VWM_CONTEXT_SHELF)
- break;
-
- /* desired == DESKTOP && focused == SHELF */
-
- VWM_TRACE("unmapping shelf window \"%s\"", vwm->focused_shelf->xwindow->name);
- vwm_win_unmap(vwm, vwm->focused_shelf);
- XFlush(VWM_XDISPLAY(vwm)); /* for a more responsive feel */
-
- /* map the focused desktop, from the top of the stack down */
- list_for_each_entry_prev(xwin, &vwm->xwindows, xwindows) {
- if (!(vwin = xwin->managed))
- continue;
-
- if (vwin->desktop == vwm->focused_desktop && !vwin->shelved) {
- VWM_TRACE("Mapping desktop window \"%s\"", xwin->name);
- vwm_win_map(vwm, vwin);
- }
- }
-
- if (vwm->focused_desktop->focused_window) {
- VWM_TRACE("Focusing \"%s\"", vwm->focused_desktop->focused_window->xwindow->name);
- XSetInputFocus(VWM_XDISPLAY(vwm), vwm->focused_desktop->focused_window->xwindow->id, RevertToPointerRoot, CurrentTime);
- }
-
- vwm->focused_context = VWM_CONTEXT_DESKTOP;
- break;
-
- case VWM_CONTEXT_DESKTOP:
- /* unmap everything, map the shelf */
- if (desired_context == VWM_CONTEXT_DESKTOP)
- break;
-
- /* desired == SHELF && focused == DESKTOP */
-
- /* there should be a focused shelf if the shelf contains any windows, we NOOP the switch if the shelf is empty. */
- if (vwm->focused_shelf) {
- /* unmap everything on the current desktop */
- list_for_each_entry(xwin, &vwm->xwindows, xwindows) {
- if (!(vwin = xwin->managed))
- continue;
-
- if (vwin->desktop == vwm->focused_desktop) {
- VWM_TRACE("Unmapping desktop window \"%s\"", xwin->name);
- vwm_win_unmap(vwm, vwin);
- }
- }
-
- XFlush(VWM_XDISPLAY(vwm)); /* for a more responsive feel */
-
- VWM_TRACE("Mapping shelf window \"%s\"", vwm->focused_shelf->xwindow->name);
- vwm_win_map(vwm, vwm->focused_shelf);
- vwm_win_focus(vwm, vwm->focused_shelf);
-
- vwm->focused_context = VWM_CONTEXT_SHELF;
- }
- break;
-
- default:
- VWM_BUG("unexpected focused context %x", vwm->focused_context);
- break;
+ VWM_TRACE("MRU context: %p", context);
+ list_move(&context->contexts_mru, &vwm->contexts_mru);
+
+ return context;
+}
+
+
+/* return next MRU context relative to the supplied context */
+vwm_context_t * vwm_context_next_mru(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction)
+{
+ list_head_t *next;
+
+ switch (direction) {
+ case VWM_DIRECTION_FORWARD:
+ if (context->contexts_mru.next == &vwm->contexts_mru) {
+ next = context->contexts_mru.next->next;
+ } else {
+ next = context->contexts_mru.next;
+ }
+ break;
+
+ case VWM_DIRECTION_REVERSE:
+ if (context->contexts_mru.prev == &vwm->contexts_mru) {
+ next = context->contexts_mru.prev->prev;
+ } else {
+ next = context->contexts_mru.prev;
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return list_entry(next, vwm_context_t, contexts_mru);
+}
+
+
+/* return next context spatially relative to the supplied context, no wrap-around */
+vwm_context_t * vwm_context_next(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction)
+{
+ switch (direction) {
+ case VWM_DIRECTION_FORWARD:
+ if (context->contexts.next != &vwm->contexts)
+ context = list_entry(context->contexts.next, vwm_context_t, contexts);
+ break;
+
+ case VWM_DIRECTION_REVERSE:
+ if (context->contexts.prev != &vwm->contexts)
+ context = list_entry(context->contexts.prev, vwm_context_t, contexts);
+ break;
+ }
+
+ return context;
+}
+
+
+/* helper for automatically assigning context colors */
+static int next_context_color_idx(vwm_t *vwm)
+{
+ int counts[VWM_CONTEXT_COLOR_MAX] = {};
+ vwm_context_t *context;
+ int color = 0;
+
+ /* TODO: contexts should probably keep a window count,
+ * so this could skip empty contexts, then those
+ * would be automatically recycled.
+ */
+ list_for_each_entry(context, &vwm->contexts, contexts)
+ counts[context->color]++;
+
+ for (int i = 0; i < NELEMS(counts); i++) {
+ if (counts[i] < counts[color])
+ color = i;
+ }
+
+ return color;
+}
+
+
+/* create a context */
+/* if color = -1 one is automatically assigned,
+ * otherwise the supplied color is used.
+ */
+vwm_context_t * vwm_context_create(vwm_t *vwm, int color, vwm_desktop_t *desktop)
+{
+ vwm_context_t *context;
+
+ context = calloc(1, sizeof(vwm_context_t));
+ if (context == NULL) {
+ VWM_PERROR("Failed to allocate context");
+ goto _fail;
+ }
+
+ if (color < 0)
+ color = next_context_color_idx(vwm);
+
+ assert(color < NELEMS(vwm->context_colors));
+
+ context->color = color;
+
+ list_add_tail(&context->contexts, &vwm->contexts);
+ list_add_tail(&context->contexts_mru, &vwm->contexts_mru);
+
+ if (!desktop)
+ desktop = vwm_desktop_create(vwm, context);
+
+ context->focused_desktop = desktop;
+
+ return context;
+
+_fail:
+ return NULL;
+}
+
+
+/* destroy a context */
+void vwm_context_destroy(vwm_t *vwm, vwm_context_t *context)
+{
+ /* silently refuse to destroy a context having windows (for now) */
+ /* there's _always_ a focused window on a context having mapped windows */
+ if (context->focused_desktop && context->focused_desktop->focused_window)
+ return;
+
+ /* also silently refuse to destroy the last context (for now) */
+ if (context->contexts.next == context->contexts.prev)
+ return;
+
+ list_del(&context->contexts);
+ list_del(&context->contexts_mru);
+}
+
+
+/* find a context by color, creating one if needed */
+vwm_context_t * vwm_context_by_color(vwm_t *vwm, unsigned color)
+{
+ vwm_context_t *context;
+
+ list_for_each_entry(context, &vwm->contexts, contexts) {
+ if (context->color == color)
+ return context;
}
- /* return if the context has been changed, the caller may need to branch differently if nothing happened */
- return (vwm->focused_context != entry_context);
+ return vwm_context_create(vwm, color, NULL);
}
© All Rights Reserved