chiark / gitweb /
5e9e5c7c4994873adc2c30dcaed004dffd25c251
[elogind.git] / src / console / consoled-workspace.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include "consoled.h"
25 #include "grdev.h"
26 #include "idev.h"
27 #include "list.h"
28 #include "macro.h"
29 #include "util.h"
30
31 int workspace_new(Workspace **out, Manager *m) {
32         _cleanup_(workspace_unrefp) Workspace *w = NULL;
33         int r;
34
35         assert(out);
36
37         w = new0(Workspace, 1);
38         if (!w)
39                 return -ENOMEM;
40
41         w->ref = 1;
42         w->manager = m;
43         LIST_PREPEND(workspaces_by_manager, m->workspace_list, w);
44
45         r = terminal_new(&w->current, w);
46         if (r < 0)
47                 return r;
48
49         *out = w;
50         w = NULL;
51         return 0;
52 }
53
54 static void workspace_cleanup(Workspace *w) {
55         Terminal *t;
56
57         assert(w);
58         assert(w->ref == 0);
59         assert(w->manager);
60         assert(!w->session_list);
61
62         w->current = NULL;
63         while ((t = w->terminal_list))
64                 terminal_free(t);
65
66         LIST_REMOVE(workspaces_by_manager, w->manager->workspace_list, w);
67         free(w);
68 }
69
70 Workspace *workspace_ref(Workspace *w) {
71         assert(w);
72
73         ++w->ref;
74         return w;
75 }
76
77 Workspace *workspace_unref(Workspace *w) {
78         if (!w)
79                 return NULL;
80
81         assert(w->ref > 0);
82
83         if (--w->ref == 0)
84                 workspace_cleanup(w);
85
86         return NULL;
87 }
88
89 Workspace *workspace_attach(Workspace *w, Session *s) {
90         assert(w);
91         assert(s);
92
93         LIST_PREPEND(sessions_by_workspace, w->session_list, s);
94         workspace_refresh(w);
95         return workspace_ref(w);
96 }
97
98 Workspace *workspace_detach(Workspace *w, Session *s) {
99         assert(w);
100         assert(s);
101         assert(s->active_ws == w);
102
103         LIST_REMOVE(sessions_by_workspace, w->session_list, s);
104         workspace_refresh(w);
105         return workspace_unref(w);
106 }
107
108 void workspace_refresh(Workspace *w) {
109         uint32_t width, height;
110         Terminal *t;
111         Session *s;
112         Display *d;
113
114         assert(w);
115
116         width = 0;
117         height = 0;
118
119         /* find out minimum dimension of all attached displays */
120         LIST_FOREACH(sessions_by_workspace, s, w->session_list) {
121                 LIST_FOREACH(displays_by_session, d, s->display_list) {
122                         assert(d->width > 0 && d->height > 0);
123
124                         if (width == 0 || d->width < width)
125                                 width = d->width;
126                         if (height == 0 || d->height < height)
127                                 height = d->height;
128                 }
129         }
130
131         /* either both are zero, or none is zero */
132         assert(!(!width ^ !height));
133
134         /* update terminal-sizes if dimensions changed */
135         if (w->width != width || w->height != height) {
136                 w->width = width;
137                 w->height = height;
138
139                 LIST_FOREACH(terminals_by_workspace, t, w->terminal_list)
140                         terminal_resize(t);
141
142                 workspace_dirty(w);
143         }
144 }
145
146 void workspace_dirty(Workspace *w) {
147         Session *s;
148
149         assert(w);
150
151         LIST_FOREACH(sessions_by_workspace, s, w->session_list)
152                 session_dirty(s);
153 }
154
155 void workspace_feed(Workspace *w, idev_data *data) {
156         assert(w);
157         assert(data);
158
159         terminal_feed(w->current, data);
160 }
161
162 bool workspace_draw(Workspace *w, const grdev_display_target *target) {
163         assert(w);
164         assert(target);
165
166         return terminal_draw(w->current, target);
167 }