1 /*
2  *  This file is part of the XForms library package.
3  *
4  *  XForms is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU Lesser General Public License as
6  *  published by the Free Software Foundation; either version 2.1, or
7  *  (at your option) any later version.
8  *
9  *  XForms is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with XForms.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 /**
20  * \file appwin.c
21  *.
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1996-2002  T.C. Zhao
24  *  All rights reserved.
25  *
26  *  Manage application windows
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "include/forms.h"
34 #include "flinternal.h"
35 
36 
37 /*****************************************************************
38  * Application window management. Data structure is grossly wrong
39  * ****TODO******
40  **************************************************************{**/
41 
42 /* some constant handlers */
43 
44 static int
handle_mapping_notify(XEvent * xev,void * user_data FL_UNUSED_ARG)45 handle_mapping_notify( XEvent * xev,
46                        void   * user_data  FL_UNUSED_ARG )
47 {
48     XRefreshKeyboardMapping( ( XMappingEvent * ) xev );
49     return 0;
50 }
51 
52 
53 /***************************************
54  ***************************************/
55 
56 static void
remove_app_win(FLI_WIN * appwin)57 remove_app_win( FLI_WIN * appwin )
58 {
59 #if FL_DEBUG >= ML_DEBUG
60     M_info( "remove_app_win", "deleting window %ld", appwin->win );
61 #endif
62 
63     if ( fli_app_win == appwin )
64         fli_app_win = appwin->next;
65     else
66     {
67         FLI_WIN *fwin = fli_app_win;
68 
69         while ( fwin && fwin->next != appwin )
70             fwin = fwin->next;
71 
72         if ( fwin )
73             fwin->next = fwin->next->next;
74         else
75         {
76             M_err( "remove_app_win", "Invalid argument" );
77             return;
78         }
79     }
80 
81     fl_free( appwin );
82 }
83 
84 
85 /***************************************
86  * Given a window find the correct structure or create one
87  ***************************************/
88 
89 static FLI_WIN *
get_fl_win_struct(Window win)90 get_fl_win_struct( Window win )
91 {
92     FLI_WIN *fwin = fli_app_win,
93             *lwin = fli_app_win;
94     size_t i;
95 
96     for ( ; fwin && fwin->win != win; lwin = fwin, fwin = fwin->next )
97         /* empty */ ;
98 
99     /* If we found it we're done */
100 
101     if ( fwin )
102         return fwin;
103 
104     /* Otherwise create a new structure and append it to the end */
105 
106 #if FL_DEBUG >= ML_DEBUG
107     M_info( "get_fl_win_struct", "Creating FLI_WIN struct for %ld", win );
108 #endif
109 
110     if ( ( fwin = fl_malloc( sizeof *fwin ) ) == NULL )
111         return NULL;
112 
113     fwin->next = NULL;
114     fwin->win = win;
115     fwin->pre_emptive = NULL;
116     fwin->pre_emptive_data = NULL;
117     for ( i = 0; i < LASTEvent; i++ )
118     {
119         fwin->callback[  i ] = NULL;
120         fwin->user_data[ i ] = NULL;
121     }
122 
123     /* Default handlers */
124 
125     fwin->callback[ MappingNotify ] = handle_mapping_notify;
126 
127     fwin->default_callback = NULL;
128     fwin->mask = 0;
129 
130     if ( ! fli_app_win )
131         fli_app_win = fwin;
132     else
133         lwin->next = fwin;
134 
135     return fwin;
136 }
137 
138 
139 /***************************************
140  ***************************************/
141 
142 FL_APPEVENT_CB
fli_set_preemptive_callback(Window win,FL_APPEVENT_CB pcb,void * data)143 fli_set_preemptive_callback( Window           win,
144                              FL_APPEVENT_CB   pcb,
145                              void           * data )
146 {
147     FLI_WIN *fwin;
148     FL_APPEVENT_CB old = NULL;
149 
150     if ( ! ( fwin = get_fl_win_struct( win ) ) )
151     {
152         M_err( "fli_set_preemptive_callback", "Memory allocation failure" );
153         return NULL;
154     }
155 
156     old = fwin->pre_emptive;
157 
158     fwin->pre_emptive      = pcb;
159     fwin->pre_emptive_data = data;
160 
161     return old;
162 }
163 
164 
165 /***************************************
166  * Add an event handler for a window
167  ***************************************/
168 
169 FL_APPEVENT_CB
fl_add_event_callback(Window win,int ev,FL_APPEVENT_CB wincb,void * user_data)170 fl_add_event_callback( Window           win,
171                        int              ev,
172                        FL_APPEVENT_CB   wincb,
173                        void *           user_data )
174 {
175     FLI_WIN *fwin;
176     int i,
177         nev;
178     FL_APPEVENT_CB old = NULL;
179 
180     if ( ev < 0 || ev >= LASTEvent )
181         return NULL;
182 
183     if ( ! ( fwin = get_fl_win_struct( win ) ) )
184     {
185         M_err( "fl_add_event_callback", "Memory allocation failure" );
186         return NULL;
187     }
188 
189     /* ev < KeyPress means all events */
190 
191     nev = ev;
192     if ( ev < KeyPress )
193     {
194         ev = KeyPress;
195         nev = LASTEvent - 1;
196     }
197 
198     for ( i = ev; i <= nev; i++ )
199     {
200         old = fwin->callback[ i ];
201         fwin->callback[ i ] = wincb;
202         fwin->user_data[ i ] = user_data;
203     }
204 
205     return old;
206 }
207 
208 
209 /***************************************
210  * Removes one or all event callbacks for a window. Might be
211  * called for a window for which no event callbacks have been
212  * set, so handle also that case gracefully.
213  ***************************************/
214 
215 void
fl_remove_event_callback(Window win,int ev)216 fl_remove_event_callback( Window win,
217                           int    ev )
218 {
219     FLI_WIN *fwin = fli_app_win;
220 
221     if ( ev < 0 || ev >= LASTEvent )
222         return;
223 
224     while ( fwin && fwin->win != win )
225         fwin = fwin->next;
226 
227     if ( ! fwin )
228         return;
229 
230     if ( ev >= KeyPress )
231     {
232         fwin->callback[ ev ] = NULL;
233         fwin->user_data[ ev ] = NULL;
234     }
235     else                         /* ev < KeyPress means all events */
236         remove_app_win( fwin );
237 }
238 
239 
240 typedef struct
241 {
242     int           event;
243     unsigned long mask;
244 } EMS;
245 
246 static EMS ems[ ] =
247 {
248     { CirculateNotify,  StructureNotifyMask },
249     { ConfigureNotify,  StructureNotifyMask },
250     { DestroyNotify,    StructureNotifyMask },
251     { CreateNotify,     StructureNotifyMask },
252     { GravityNotify,    StructureNotifyMask },
253     { MapNotify,        StructureNotifyMask },
254     { ReparentNotify,   StructureNotifyMask },
255     { UnmapNotify,      StructureNotifyMask },
256     { CirculateRequest, SubstructureRedirectMask },
257     { ConfigureRequest, SubstructureRedirectMask },
258     { MapRequest,       SubstructureRedirectMask },
259     { ResizeRequest,    ResizeRedirectMask },
260     { Expose,           ExposureMask },
261     { EnterNotify,      EnterWindowMask },
262     { LeaveNotify,      LeaveWindowMask },
263     { KeyPress,         KeyPressMask },
264     { KeyRelease,       KeyReleaseMask} ,
265     { ButtonPress,        ButtonPressMask
266                      /* | OwnerGrabButtonMask */ },
267     { ButtonRelease,      ButtonReleaseMask
268                      /* | OwnerGrabButtonMask */ },
269     { MotionNotify,       PointerMotionMask
270                         | ButtonMotionMask
271                         | PointerMotionHintMask },
272     { FocusIn,          FocusChangeMask },
273     { FocusOut,         FocusChangeMask },
274     { KeymapNotify,     KeymapStateMask },
275     { PropertyNotify,   PropertyChangeMask },
276     { VisibilityNotify, VisibilityChangeMask },
277     { ColormapNotify,   ColormapChangeMask },
278  /* non-maskable events */
279     { MappingNotify,    0 },
280     { SelectionNotify,  0 },
281     { SelectionRequest, 0 },
282     { SelectionClear,   0 },
283     { ClientMessage,    0 },
284     { GraphicsExpose,   0 },
285     { NoExpose,         0 }
286 };
287 
288 
289 /***************************************
290  ***************************************/
291 
292 unsigned long
fli_xevent_to_mask(int event)293 fli_xevent_to_mask( int event )
294 {
295     EMS *em = ems,
296         *eme = ems + sizeof ems / sizeof *ems;
297 
298     for ( ; em < eme; em++ )
299         if ( em->event == event )
300             return em->mask;
301 
302     return 0;
303 }
304 
305 
306 /***************************************
307  ***************************************/
308 
309 void
fl_activate_event_callbacks(Window win)310 fl_activate_event_callbacks( Window win )
311 {
312     FLI_WIN *fwin = fli_app_win;
313     int i;
314     unsigned long mask;
315 
316     while ( fwin && fwin->win != win )
317         fwin = fwin->next;
318 
319     if ( ! fwin )
320     {
321         M_err( "fl_activate_event_callbacks", "Unknown window %ld", win );
322         return;
323     }
324 
325     /* Solicit all registered events */
326 
327     for ( mask = i = 0; i < LASTEvent; i++ )
328         if ( fwin->callback[ i ] )
329             mask |= fli_xevent_to_mask( i );
330 
331     XSelectInput( flx->display, win, mask );
332 }
333 
334 
335 /***************************************
336  ***************************************/
337 
338 void
fl_winclose(Window win)339 fl_winclose( Window win )
340 {
341     XEvent xev;
342 
343     XUnmapWindow( flx->display, win );
344     XDestroyWindow( flx->display, win );
345 
346     XSync( flx->display, 0 );
347 
348     while ( XCheckWindowEvent( flx->display, win, AllEventsMask, &xev ) )
349         fli_xevent_name( "Eaten", &xev );
350 
351     fl_remove_event_callback( win, 0 );
352 }
353 
354 
355 /*
356  * Local variables:
357  * tab-width: 4
358  * indent-tabs-mode: nil
359  * End:
360  */
361