CTWM
Toggle main menu visibility
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
18
static
DFHANDLER
(nop);
19
static
DFHANDLER
(separator);
20
static
DFHANDLER
(title);
21
static
DFHANDLER
(deltastop);
22
static
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
*/
45
int
RootFunction
= 0;
46
47
48
/*
49
* Track whether a window gets moved by move operations: used for
50
* f.deltastop handling.
51
*/
52
bool
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
*/
65
bool
func_reset_cursor
;
66
67
/*
68
* Time of various actions: used in ConstrainedMoveTime related bits in
69
* some window moving/resizing.
70
*/
71
Time
last_time
= 0;
72
73
74
static
bool
EF_main
(
EF_FULLPROTO
);
75
76
static
bool
DeferExecution
(
int
context,
int
func, Cursor cursor);
77
static
bool
should_defer
(
int
func);
78
static
Cursor
defer_cursor
(
int
func);
79
static
Cursor
NeedToDefer
(
MenuRoot
*
root
);
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
*/
98
void
99
ExecuteFunction
(
EF_FULLPROTO
)
100
{
101
EF_main
(
EF_ARGS
);
102
}
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
*/
114
static
bool
115
EF_main
(
EF_FULLPROTO
)
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,
217
ButtonPressMask | ButtonReleaseMask,
218
GrabModeAsync, GrabModeAsync,
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: {
252
MenuRoot
*mroot;
253
MenuItem
*mitem;
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,
272
tmp_win, eventp, context, pulldown);
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) {
322
XUngrabPointer(
dpy
, CurrentTime);
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
*/
342
static
Cursor
LastCursor
;
343
344
void
345
ReGrab
(
void
)
346
{
347
XGrabPointer(
dpy
,
Scr
->Root, True,
348
ButtonPressMask | ButtonReleaseMask,
349
GrabModeAsync, GrabModeAsync,
350
Scr
->Root,
LastCursor
, CurrentTime);
351
}
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
*/
366
static
bool
367
DeferExecution
(
int
context,
int
func, Cursor cursor)
368
{
369
Window confine_to =
Scr
->Root;
370
#ifdef CAPTIVE
371
if
(func == F_ADOPTWINDOW) {
372
confine_to = None;
373
}
374
#endif
375
376
if
((context ==
C_ROOT
) || (context ==
C_ALTERNATE
)) {
377
LastCursor
= cursor;
378
XGrabPointer(
dpy
,
379
Scr
->Root,
380
True,
381
ButtonPressMask | ButtonReleaseMask,
382
GrabModeAsync,
383
GrabModeAsync,
384
confine_to,
385
cursor,
386
CurrentTime);
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
412
static
bool
413
should_defer
(
int
func)
414
{
415
/* Outside the table -> "No" */
416
if
(func < 0 || func >= fdef_table_max) {
417
return
false
;
418
}
419
420
if
(fdef_table[func] != DC_NONE) {
421
return
true
;
422
}
423
return
false
;
424
}
425
426
static
Cursor
427
defer_cursor
(
int
func)
428
{
429
/* Outside the table -> "No" */
430
if
(func < 0 || func >= fdef_table_max) {
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
*/
465
static
Cursor
466
NeedToDefer
(
MenuRoot
*
root
)
467
{
468
MenuItem
*mitem;
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 */
495
static
496
DFHANDLER
(nop)
497
{
498
fprintf(stderr,
"%s(): Shouldn't get here.\n"
, __func__);
499
return
;
500
}
501
static
502
DFHANDLER
(separator)
503
{
504
fprintf(stderr,
"%s(): Shouldn't get here.\n"
, __func__);
505
return
;
506
}
507
static
508
DFHANDLER
(title)
509
{
510
fprintf(stderr,
"%s(): Shouldn't get here.\n"
, __func__);
511
return
;
512
}
513
514
/* f.deltastop and f.function are magic */
515
static
516
DFHANDLER
(deltastop)
517
{
518
fprintf(stderr,
"%s(): Shouldn't get here.\n"
, __func__);
519
return
;
520
}
521
static
522
DFHANDLER
(function)
523
{
524
fprintf(stderr,
"%s(): Shouldn't get here.\n"
, __func__);
525
return
;
526
}
ctwm.h
ProgramName
char * ProgramName
Definition
ctwm_main.c:146
dpy
Display * dpy
Definition
ctwm_main.c:84
C_ROOT
#define C_ROOT
Definition
ctwm.h:78
C_ALTERNATE
#define C_ALTERNATE
Definition
ctwm.h:83
Scr
#define Scr
Cancel
bool Cancel
Definition
event_core.c:94
ButtonPressed
int ButtonPressed
Definition
event_core.c:93
events.h
ExecuteFunction
void ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition
functions.c:99
WindowMoved
bool WindowMoved
Definition
functions.c:52
DeferExecution
static bool DeferExecution(int context, int func, Cursor cursor)
Definition
functions.c:367
func_reset_cursor
bool func_reset_cursor
Definition
functions.c:65
should_defer
static bool should_defer(int func)
Definition
functions.c:413
EF_main
static bool EF_main(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition
functions.c:115
LastCursor
static Cursor LastCursor
Definition
functions.c:342
NeedToDefer
static Cursor NeedToDefer(MenuRoot *root)
Definition
functions.c:466
last_time
Time last_time
Definition
functions.c:71
RootFunction
int RootFunction
Definition
functions.c:45
ReGrab
void ReGrab(void)
Definition
functions.c:345
defer_cursor
static Cursor defer_cursor(int func)
Definition
functions.c:427
functions.h
functions_internal.h
DFHANDLER
#define DFHANDLER(func)
Definition
functions_internal.h:19
EF_ARGS
#define EF_ARGS
Definition
functions_internal.h:13
EF_FULLPROTO
#define EF_FULLPROTO
Definition
functions_internal.h:10
FindMenuRoot
MenuRoot * FindMenuRoot(char *name)
Definition
menus.c:1503
root
MenuRoot * root
Definition
parse_yacc.c:26
screen.h
MenuItem
Definition
menus.h:48
MenuItem::next
struct MenuItem * next
Definition
menus.h:49
MenuItem::func
short func
Definition
menus.h:59
MenuItem::action
char * action
Definition
menus.h:54
MenuRoot
Definition
menus.h:66
MenuRoot::first
struct MenuItem * first
Definition
menus.h:67
functions.c
Generated by
1.18.0