1 /* vifm
2 * Copyright (C) 2014 xaizek.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "cancellation.h"
20
21 #include <curses.h> /* noraw() raw() */
22
23 #include <assert.h> /* assert() */
24
25 #include "../utils/cancellation.h"
26 #include "../utils/int_stack.h"
27 #include "../status.h"
28
29 /* State of cancellation request processing. */
30 typedef enum
31 {
32 CRS_DISABLED, /* Cancellation is disabled. */
33 CRS_DISABLED_REQUESTED, /* Cancellation is disabled and was requested. */
34 CRS_ENABLED, /* Cancellation is enabled, but wasn't requested. */
35 CRS_ENABLED_REQUESTED, /* Cancellation is enabled and was requested. */
36 }
37 cancellation_request_state;
38
39 static int ui_cancellation_hook(void *arg);
40 static int ui_cancellation_enabled(void);
41 static int is_enabled(cancellation_request_state state);
42
43 const cancellation_t ui_cancellation_info = { .hook = &ui_cancellation_hook };
44
45 /* Whether cancellation was requested. Used by ui_cancellation_* group of
46 * functions. */
47 static cancellation_request_state cancellation_state;
48
49 /* Previous cancellation states. */
50 static int_stack_t cancellation_stack;
51
52 /* Implementation of cancellation hook for. */
53 static int
ui_cancellation_hook(void * arg)54 ui_cancellation_hook(void *arg)
55 {
56 return ui_cancellation_requested();
57 }
58
59 void
ui_cancellation_push_on(void)60 ui_cancellation_push_on(void)
61 {
62 int_stack_push(&cancellation_stack, cancellation_state);
63
64 if(!ui_cancellation_enabled())
65 {
66 ui_cancellation_enable();
67 }
68
69 cancellation_state = CRS_ENABLED;
70 }
71
72 void
ui_cancellation_push_off(void)73 ui_cancellation_push_off(void)
74 {
75 int_stack_push(&cancellation_stack, cancellation_state);
76
77 if(ui_cancellation_enabled())
78 {
79 ui_cancellation_disable();
80 }
81
82 cancellation_state = CRS_DISABLED;
83 }
84
85 void
ui_cancellation_enable(void)86 ui_cancellation_enable(void)
87 {
88 /* TODO: consider enabling this assert:
89 assert(!int_stack_is_empty(&cancellation_stack) && "Must push state first.");
90 */
91 assert(!ui_cancellation_enabled() && "Can't enable twice in a row.");
92
93 cancellation_state = (cancellation_state == CRS_DISABLED)
94 ? CRS_ENABLED
95 : CRS_ENABLED_REQUESTED;
96
97 /* The check is here for tests, which are running with uninitialized
98 * curses. */
99 if(curr_stats.load_stage > 2)
100 {
101 /* Temporary disable raw mode of terminal so that Ctrl-C is handled as
102 * SIGINT signal rather than as regular input character. */
103 noraw();
104 }
105 }
106
107 void
ui_cancellation_request(void)108 ui_cancellation_request(void)
109 {
110 if(ui_cancellation_enabled())
111 {
112 cancellation_state = CRS_ENABLED_REQUESTED;
113 }
114 }
115
116 int
ui_cancellation_requested(void)117 ui_cancellation_requested(void)
118 {
119 return cancellation_state == CRS_ENABLED_REQUESTED
120 || cancellation_state == CRS_DISABLED_REQUESTED;
121 }
122
123 void
ui_cancellation_disable(void)124 ui_cancellation_disable(void)
125 {
126 /* TODO: consider enabling this assert:
127 assert(!int_stack_is_empty(&cancellation_stack) && "Must push state first.");
128 */
129 assert(ui_cancellation_enabled() && "Can't disable what disabled.");
130
131 /* The check is here for tests, which are running with uninitialized
132 * curses. */
133 if(curr_stats.load_stage > 2)
134 {
135 /* Restore raw mode of terminal so that Ctrl-C is handled as regular input
136 * character rather than as SIGINT signal. */
137 raw();
138 }
139
140 cancellation_state = (cancellation_state == CRS_ENABLED_REQUESTED)
141 ? CRS_DISABLED_REQUESTED
142 : CRS_DISABLED;
143 }
144
145 void
ui_cancellation_pop(void)146 ui_cancellation_pop(void)
147 {
148 assert(!int_stack_is_empty(&cancellation_stack) && "Underflow.");
149
150 cancellation_request_state next = int_stack_get_top(&cancellation_stack);
151
152 if(ui_cancellation_enabled())
153 {
154 if(!is_enabled(next))
155 {
156 ui_cancellation_disable();
157 }
158 }
159 else
160 {
161 if(is_enabled(next))
162 {
163 ui_cancellation_enable();
164 }
165 }
166
167 int_stack_pop(&cancellation_stack);
168 cancellation_state = next;
169 }
170
171 /* Checks whether cancellation processing is enabled. Returns non-zero if so,
172 * otherwise zero is returned. */
173 static int
ui_cancellation_enabled(void)174 ui_cancellation_enabled(void)
175 {
176 return is_enabled(cancellation_state);
177 }
178
179 /* Checks if state is an enabled state. Returns non-zero if so, otherwise zero
180 * is returned. */
181 static int
is_enabled(cancellation_request_state state)182 is_enabled(cancellation_request_state state)
183 {
184 return state == CRS_ENABLED
185 || state == CRS_ENABLED_REQUESTED;
186 }
187
188 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
189 /* vim: set cinoptions+=t0 filetype=c : */
190