CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/functions.c
Go to the documentation of this file.
1/*
2 * Dispatcher for our f.whatever functions
3 */
4
5
6#include "ctwm.h"
7
8#include <stdio.h>
9
10#include "events.h"
11#include "functions.h"
12#include "functions_defs.h"
13#include "functions_deferral.h" // Generated deferral table
14#include "functions_internal.h"
15#include "screen.h"
16
17
18static DFHANDLER(nop);
19static DFHANDLER(separator);
20static DFHANDLER(title);
21static DFHANDLER(deltastop);
22static DFHANDLER(function);
23
24/*
25 * The generated dispatch table. Have to do this after the preceeding
26 * prototypes for the handers in this file, since those funcs are ref'd
27 * in this table.
28 */
29#include "functions_dispatch_execution.h"
30
31
32/*
33 * Various functions can be executed "from the root" (which generally
34 * means "from a menu"), but apply to a specific window (e.g., f.move,
35 * f.identify, etc). You obviously can't be selecting it from a menu and
36 * pointing at the window to target at the same time, so we have to
37 * 2-step those calls. This happens via the DeferExecution() call in the
38 * implementations of those functions, which stashes the "in progress"
39 * function in RootFunction. The HandleButtonPress() event handler will
40 * later notice that and loop events back around into ExecuteFunction()
41 * again to pick up where it left off.
42 *
43 * (a more descriptive name might be in order)
44 */
46
47
48/*
49 * Track whether a window gets moved by move operations: used for
50 * f.deltastop handling.
51 */
52bool WindowMoved = false;
53
54/*
55 * Whether the cursor needs to be reset from a way we've altered it in
56 * the process of running functions. This is used to determine whether
57 * we're ungrabbing the pointer to reset back from setting the WaitCursor
58 * early on in the execution process. X-ref the XXX comment on that;
59 * it's unclear as to whether we should even be doing this anymore, but
60 * since we are, we use a global to ease tracking whether we need to
61 * unset it. There are cases deeper down in function handling that may
62 * do their own fudgery and want the pointer left alone after they
63 * return.
64 */
66
67/*
68 * Time of various actions: used in ConstrainedMoveTime related bits in
69 * some window moving/resizing.
70 */
72
73
74static bool EF_main(EF_FULLPROTO);
75
76static bool DeferExecution(int context, int func, Cursor cursor);
77static bool should_defer(int func);
78static Cursor defer_cursor(int func);
80
81
82/***********************************************************************
83 *
84 * Procedure:
85 * ExecuteFunction - execute a twm root function
86 *
87 * Inputs:
88 * func - the function to execute
89 * action - the menu action to execute
90 * w - the window to execute this function on
91 * tmp_win - the twm window structure
92 * event - the event that caused the function
93 * context - the context in which the button was pressed
94 * pulldown- flag indicating execution from pull down menu
95 *
96 ***********************************************************************
97 */
98void
103
104/*
105 * Main ExecuteFunction body; returns true if we should continue a
106 * f.function's progress, false if we should stop.
107 *
108 * This is separate because only the recursive calls in f.function
109 * handling care about that return. The only possible way to get to a
110 * false return is via f.deltastop triggering. We can't do it just with
111 * a global, since f.function can at least in theory happen recursively;
112 * I don't know how well it would actually work, but it has a chance.
113 */
114static bool
116{
117 /* This should always start out clear when we come in here */
118 RootFunction = 0;
119
120 /* Early escape for cutting out of things */
121 if(Cancel) {
122 /*
123 * Strictly, this could probably be false, since if it's set it
124 * would mean it'll just happen again when we iterate back
125 * through for the next action. Once set, it only gets unset in
126 * the ButtonRelease handler, which I don't think would ever get
127 * called in between pieces of a f.function call. But I can't be
128 * sure, so just go ahead and return true, and we'll eat a few
129 * extra loops of function calls and insta-returns if it happens.
130 */
131 return true;
132 }
133
134
135 /*
136 * More early escapes; some "functions" don't actually do anything
137 * when executed, and exist for magical purposes elsewhere. So just
138 * skip out early if we try running them.
139 */
140 switch(func) {
141 case F_NOP:
142 case F_SEPARATOR:
143 case F_TITLE:
144 return true;
145
146 default:
147 ; /* FALLTHRU */
148 }
149
150
151 /*
152 * Is this a function that needs some deferring? If so, go ahead and
153 * do that. Note that this specifically doesn't handle the special
154 * case of f.function; it has to do its own checking for whether
155 * there's something to defer.
156 */
157 if(should_defer(func)) {
158 /* Figure the cursor */
159 Cursor dc = defer_cursor(func);
160 if(dc == None) {
161 dc = Scr->SelectCursor;
162 }
163
164 /* And defer (if we're in a context that needs to) */
165 if(DeferExecution(context, func, dc)) {
166 return true;
167 }
168 }
169
170
171 /*
172 * For most functions with a few exceptions, grab the pointer.
173 *
174 * This is actually not a grab so much to take control of the
175 * pointer, as to set the cursor. Apparently, xlib doesn't
176 * distinguish the two. The functions that need it in a "take
177 * control" sense (like the move and resize bits) should all be doing
178 * their own explicit grabs to handle that.
179 *
180 * XXX I have no idea why there's the exclusion list. Apart from
181 * adding 1 or 2 functions, this code comes verbatim from twm, which
182 * has no history or documentation as to why it's happening.
183 *
184 * XXX I'm not sure this is even worth doing anymore. The point of
185 * the WaitCursor is to let the user know "yeah, I'm working on it",
186 * during operations that may take a while. On 1985 hardware, that
187 * would be "almost anything you do". But in the 21st century, what
188 * functions could fall into that category, and need to give some
189 * user feedback before either finishing or doing something that
190 * gives other user feedback anyway?
191 */
192 func_reset_cursor = false;
193 switch(func) {
194 case F_UPICONMGR:
195 case F_LEFTICONMGR:
196 case F_RIGHTICONMGR:
197 case F_DOWNICONMGR:
198 case F_FORWICONMGR:
199 case F_BACKICONMGR:
200 case F_NEXTICONMGR:
201 case F_PREVICONMGR:
202 case F_NOP:
203 case F_TITLE:
204 case F_DELTASTOP:
205 case F_RAISELOWER:
206 case F_WARPTOSCREEN:
207 case F_WARPTO:
208 case F_WARPRING:
209 case F_WARPTOICONMGR:
210 case F_COLORMAP:
211 case F_ALTKEYMAP:
212 case F_ALTCONTEXT:
213 break;
214
215 default: {
216 XGrabPointer(dpy, Scr->Root, True,
219 Scr->Root, Scr->WaitCursor, CurrentTime);
220 func_reset_cursor = true;
221 break;
222 }
223 }
224
225
226 /*
227 * Main dispatching/executing.
228 *
229 * _Most_ f.things are dispatched to individual handler functions,
230 * but we keep the magic related to f.function/f.deltastop out here
231 * to free the inner bits from having to care about the magic
232 * returns.
233 */
234 switch(func) {
235 case F_DELTASTOP:
236 if(WindowMoved) {
237 /*
238 * If we're returning false here, it's because we were in
239 * the midst of a f.function, and we should stop. That
240 * means when we return from here it'll be into the false
241 * case in the F_FUNCTION handler below, which will break
242 * right out and fall through to the end of this
243 * function, which will do the post-function cleanup
244 * bits. That means we don't need to try and break out
245 * to them here, we can just return straight off.
246 */
247 return false;
248 }
249 break;
250
251 case F_FUNCTION: {
254 Cursor curs;
255
256 if((mroot = FindMenuRoot(action)) == NULL) {
257 if(!action) {
258 action = "undef";
259 }
260 fprintf(stderr, "%s: couldn't find function \"%s\"\n",
261 ProgramName, (char *)action);
262 return true;
263 }
264
265 if((curs = NeedToDefer(mroot)) != None
266 && DeferExecution(context, func, curs)) {
267 return true;
268 }
269 else {
270 for(mitem = mroot->first; mitem != NULL; mitem = mitem->next) {
271 bool r = EF_main(mitem->func, mitem->action, w,
273 if(r == false) {
274 /* pebl FIXME: the focus should be updated here,
275 or the function would operate on the same window */
276 break;
277 }
278 }
279 }
280
281 break;
282 }
283
284
285 /*
286 * Everything else is programmatically dispatched.
287 */
288 default: {
289 if(func >= 0 && func < num_f_dis && func_dispatch[func] != NULL) {
290 (*func_dispatch[func])(EF_ARGS);
291 break;
292 }
293
294 /*
295 * Getting here means somehow it wasn't in the dispatch
296 * table, which shouldn't be possible without a big bug
297 * somewhere...
298 */
299 fprintf(stderr, "Internal error: no handler for function %d\n",
300 func);
301 break;
302 }
303 }
304
305
306
307 /*
308 * Release the pointer. This should mostly mean actually "reset
309 * cursor", and be the complementary op to setting the cursor earlier
310 * up top.
311 *
312 * ButtonPressed == -1 means that we didn't get here via some sort of
313 * mouse clickery. If we did, then we presume that has some
314 * ownership of the pointer we don't want to relinquish yet. And we
315 * don't have to, as the ButtonRelease handler will take care of
316 * things when it fires anyway.
317 *
318 * This has a similar XXX to the cursor setting earlier, as to
319 * whether it ought to exist.
320 */
321 if(func_reset_cursor && ButtonPressed == -1) {
323 func_reset_cursor = false;
324 }
325
326 return true;
327}
328
329
330
331/*
332 * Implementation of function deferral
333 */
334
335/*
336 * Setting a last cursor and re-grabbing to it. This is used in the
337 * AddWindow() process. It might grab the mouse and re-set the
338 * cursor away from us, and so it needs a way to set it back.
339 *
340 * XXX This begs for renaming...
341 */
343
344void
352
353
354/*
355 * Check to see if a function (implicitly, a window-targetting function)
356 * is happening in a context away from an actual window, and if so stash
357 * up info about what's in progress and return true to tell the caller to
358 * end processing the function (for now). X-ref comment on RootFunction
359 * variable definition for details.
360 *
361 * Inputs:
362 * context - the context in which the mouse button was pressed
363 * func - the function to defer
364 * cursor - the cursor to display while waiting
365 */
366static bool
367DeferExecution(int context, int func, Cursor cursor)
368{
369 Window confine_to = Scr->Root;
370#ifdef CAPTIVE
371 if(func == F_ADOPTWINDOW) {
373 }
374#endif
375
376 if((context == C_ROOT) || (context == C_ALTERNATE)) {
377 LastCursor = cursor;
379 Scr->Root,
380 True,
385 cursor,
387 RootFunction = func;
388
389 return true;
390 }
391
392 return false;
393}
394
395
396/*
397 * Various determinates of whether a function should be deferred if its
398 * called in a general (rather than win-specific) context, and what
399 * cursor should be used in the meantime.
400 *
401 * We define a big lookup array to do it. We have to indirect through an
402 * intermediate enum value instead of just the cursor since it isn't
403 * available at compile time, and we can't just make it a pointer into
404 * Scr since there are [potentially] multiple Scr's anyway. And we need
405 * an explicit unused DC_NONE value so our real values are all non-zero;
406 * the ones we don't explicitly set get initialized to 0, which we can
407 * then take as a flag saying "we don't defer this func".
408 *
409 * fdef_table in functions_deferral.h generated from functions_defs.list.
410 */
411
412static bool
414{
415 /* Outside the table -> "No" */
417 return false;
418 }
419
420 if(fdef_table[func] != DC_NONE) {
421 return true;
422 }
423 return false;
424}
425
426static Cursor
428{
429 /* Outside the table -> "No" */
431 return None;
432 }
433
434 switch(fdef_table[func]) {
435 case DC_SELECT:
436 return Scr->SelectCursor;
437 case DC_MOVE:
438 return Scr->MoveCursor;
439 case DC_DESTROY:
440 return Scr->DestroyCursor;
441
442 default:
443 /* Is there a better choice? */
444 return None;
445 }
446
447 /* NOTREACHED */
448 return None;
449}
450
451
452/*
453 * Checks each function in a user-defined Function list called via
454 * f.function to see any of them need to be defered. The Function config
455 * action creates pseudo-menus to store the items in that call, so we
456 * loop through the "items" in that "menu". Try not to think about that
457 * too much.
458 *
459 * This previously used a hardcoded list of functions to defer, which was
460 * substantially smaller than the list it's currently checking. It now
461 * checks all the same functions that are themselves checked
462 * individually, which is almost certainly how it should have always
463 * worked anyway.
464 */
465static Cursor
467{
469
470 for(mitem = root->first; mitem != NULL; mitem = mitem->next) {
471 if(should_defer(mitem->func)) {
472 Cursor dc = defer_cursor(mitem->func);
473 if(dc == None) {
474 return Scr->SelectCursor;
475 }
476 return dc;
477 }
478 }
479 return None;
480}
481
482
483
484/*
485 * Faked up handlers for functions that shouldn't ever really get to
486 * them. These are handled in various hard-coded ways before we get to
487 * automatic dispatch, so there shouldn't be any way these functions
488 * actually get called. But, just in case, return instead of dying.
489 *
490 * It's easier to just write these than to try and long-term parameterize
491 * which we expect to exist.
492 */
493
494/* f.nop, f.title, f.separator really only exist to make lines in menus */
495static
497{
498 fprintf(stderr, "%s(): Shouldn't get here.\n", __func__);
499 return;
500}
501static
503{
504 fprintf(stderr, "%s(): Shouldn't get here.\n", __func__);
505 return;
506}
507static
509{
510 fprintf(stderr, "%s(): Shouldn't get here.\n", __func__);
511 return;
512}
513
514/* f.deltastop and f.function are magic */
515static
517{
518 fprintf(stderr, "%s(): Shouldn't get here.\n", __func__);
519 return;
520}
521static
523{
524 fprintf(stderr, "%s(): Shouldn't get here.\n", __func__);
525 return;
526}
static int PlaceX
Definition add_window.c:82
char * ProgramName
Definition ctwm_main.c:146
Display * dpy
Definition ctwm_main.c:84
#define C_ROOT
Definition ctwm.h:78
#define C_ALTERNATE
Definition ctwm.h:83
#define Scr
bool Cancel
Definition event_core.c:94
int ButtonPressed
Definition event_core.c:93
void ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition functions.c:99
bool WindowMoved
Definition functions.c:52
static bool DeferExecution(int context, int func, Cursor cursor)
Definition functions.c:367
bool func_reset_cursor
Definition functions.c:65
static bool should_defer(int func)
Definition functions.c:413
static bool EF_main(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition functions.c:115
static Cursor LastCursor
Definition functions.c:342
static Cursor NeedToDefer(MenuRoot *root)
Definition functions.c:466
Time last_time
Definition functions.c:71
int RootFunction
Definition functions.c:45
void ReGrab(void)
Definition functions.c:345
static Cursor defer_cursor(int func)
Definition functions.c:427
#define DFHANDLER(func)
#define EF_ARGS
#define EF_FULLPROTO
MenuRoot * FindMenuRoot(char *name)
Definition menus.c:1503
MenuRoot * root
Definition parse_yacc.c:26
struct MenuItem * first
Definition menus.h:67