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 forms.c
21  *
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  *  Main event dispatcher.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <ctype.h>
34 #include "include/forms.h"
35 #include "flinternal.h"
36 #include "private/flvasprintf.h"
37 
38 
39 #define PointToPixel( a )     FL_crnd( ( a ) * fl_dpi / 72.0   )
40 #define MMToPixel( a )        FL_crnd( ( a ) * fl_dpi / 25.4   )
41 #define CMMToPixel( a )       FL_crnd( ( a ) * fl_dpi / 2540.0 )
42 #define CPointToPixel( a )    FL_crnd( ( a ) * fl_dpi / 7200.0 )
43 
44 static FL_FORM * create_new_form( FL_Coord,
45                                   FL_Coord );
46 static void force_visible( FL_FORM * );
47 static void set_form_property( FL_FORM *,
48                                unsigned int );
49 static void get_decoration_sizes_from_wm( Atom ,
50                                           FL_FORM *,
51                                           int *,
52                                           int *,
53                                           int *,
54                                           int * );
55 static void get_decorations_sizes_from_parent( FL_FORM *,
56                                                int *,
57                                                int *,
58                                                int *,
59                                                int * );
60 
61 
62 static FL_FORM * fli_mainform;
63 static int nomainform;
64 static int reopened_group = 0;
65 
66 FL_FORM * fli_fast_free_object = NULL;    /* exported to objects.c */
67 
68 static int has_initial;
69 
70 
71 /***************************************
72  * Returns the index of a form in the list of visible forms
73  * (or -1 if the form isn't in this list)
74  ***************************************/
75 
76 int
fli_get_visible_forms_index(FL_FORM * form)77 fli_get_visible_forms_index( FL_FORM * form )
78 {
79     int i;
80 
81     for ( i = 0; i < fli_int.formnumb; i++ )
82         if ( fli_int.forms[ i ] == form )
83             return i;
84 
85     return -1;
86 }
87 
88 
89 /***************************************
90  * Returns the index of a form in the list of hidden forms
91  * (or -1 if the form isn't in this list)
92  ***************************************/
93 
94 static int
get_hidden_forms_index(FL_FORM * form)95 get_hidden_forms_index( FL_FORM * form )
96 {
97     int i;
98 
99     for ( i = fli_int.formnumb;
100           i < fli_int.formnumb + fli_int.hidden_formnumb; i++ )
101         if ( fli_int.forms[ i ] == form )
102             return i;
103 
104     return -1;
105 }
106 
107 
108 /***************************************
109  * Extend the list of forms by one element and appends the
110  * new forms address (listing it as invisible)
111  ***************************************/
112 
113 static void
add_form_to_hidden_list(FL_FORM * form)114 add_form_to_hidden_list( FL_FORM * form )
115 {
116     fli_int.forms = realloc( fli_int.forms,
117                              ( fli_int.formnumb + fli_int.hidden_formnumb + 1 )
118                              * sizeof *fli_int.forms );
119     fli_int.forms[ fli_int.formnumb + fli_int.hidden_formnumb++ ] = form;
120 }
121 
122 
123 /***************************************
124  * Moves a form from the list of hidden to the list of visible forms
125  ***************************************/
126 
127 static int
move_form_to_visible_list(FL_FORM * form)128 move_form_to_visible_list( FL_FORM * form )
129 {
130     int i;
131 
132     /* Find the index of the hidden form */
133 
134     if (    fli_int.hidden_formnumb == 0
135          || ( i = get_hidden_forms_index( form ) ) < 0 )
136     {
137         M_err( "move_form_to_visble_list", "Form not in hidden list" );
138         return -1;
139     }
140 
141     /* If it's not at the very start of the hidden list exchange it
142        with the one at the start */
143 
144     if ( i != fli_int.formnumb )
145     {
146         fli_int.forms[ i ] = fli_int.forms[ fli_int.formnumb ];
147         fli_int.forms[ fli_int.formnumb ] = form;
148     }
149 
150     fli_int.hidden_formnumb--;
151 
152     if ( form->num_auto_objects > 0 )
153         fli_int.auto_count++;
154 
155     return ++fli_int.formnumb;
156 }
157 
158 
159 /***************************************
160  * Moves a form from the list of visible to the list of hidden forms
161  ***************************************/
162 
163 static int
move_form_to_hidden_list(FL_FORM * form)164 move_form_to_hidden_list( FL_FORM * form )
165 {
166     int i;
167 
168     /* Find the index of the form to be moved to the hidden list */
169 
170     if (    fli_int.formnumb == 0
171          || ( i = fli_get_visible_forms_index( form ) ) < 0 )
172     {
173         M_err( "move_form_to_hidden_list", "Form not in visible list" );
174         return -1;
175     }
176 
177     /* Unless the form is the last in the visible list exchange it with
178        the form at the end of the visible list */
179 
180     if ( i != --fli_int.formnumb )
181     {
182         fli_int.forms[ i ] = fli_int.forms[ fli_int.formnumb ];
183         fli_int.forms[ fli_int.formnumb ] = form;
184     }
185 
186     fli_int.hidden_formnumb++;
187 
188     if ( form->num_auto_objects > 0 )
189     {
190         if ( fli_int.auto_count == 0 )
191             M_err( "move_form_to_hidden_list", "Bad auto count" );
192         else
193             fli_int.auto_count--;
194     }
195 
196     return fli_int.formnumb;
197 }
198 
199 
200 /***************************************
201  * Removes a form from the list of hidden forms,
202  * shortening the list in the process
203  ***************************************/
204 
205 int
remove_form_from_hidden_list(FL_FORM * form)206 remove_form_from_hidden_list( FL_FORM * form )
207 {
208     int i;
209 
210     /* Find the index of the form to be removed completely from the
211        hidden list */
212 
213     if (    fli_int.hidden_formnumb == 0
214          || ( i = get_hidden_forms_index( form ) ) < 0 )
215     {
216         M_err( "remove_form_from_hidden_list", "Form not in hidden list" );
217         return -1;
218     }
219 
220     /* If it's not the form at the end of the hidden list exchange it with
221        the one at the end */
222 
223     if ( i != fli_int.formnumb + --fli_int.hidden_formnumb )
224         fli_int.forms[ i ] =
225                    fli_int.forms[ fli_int.formnumb + fli_int.hidden_formnumb ];
226 
227     /* Shorten the list of visible and hidden forms by one element */
228 
229     fli_int.forms = fl_realloc( fli_int.forms,
230                                 ( fli_int.formnumb + fli_int.hidden_formnumb )
231                                 * sizeof *fli_int.forms );
232 
233     return fli_int.formnumb;
234 }
235 
236 
237 /***************************************
238  * Returns the (visible) form that's shown in 'win'
239  ***************************************/
240 
241 FL_FORM *
fl_win_to_form(Window win)242 fl_win_to_form( Window win )
243 {
244     int i;
245 
246     if ( win == None )
247         return NULL;
248 
249     for ( i = 0; i < fli_int.formnumb; i++ )
250         if ( fli_int.forms[ i ]->window == win )
251             return fli_int.forms[ i ];
252 
253     return NULL;
254 }
255 
256 
257 /***************************************
258  * Creates a new, empty form
259  ***************************************/
260 
261 static FL_FORM *
create_new_form(FL_Coord w,FL_Coord h)262 create_new_form( FL_Coord w,
263                  FL_Coord h )
264 {
265     FL_FORM *form;
266 
267     form = fl_calloc( 1, sizeof *form );
268 
269     /* Convert non-pixel unit into pixles */
270 
271     switch ( fli_cntl.coordUnit )
272     {
273         case FL_COORD_PIXEL :
274             break;
275 
276         case FL_COORD_MM :
277             w = MMToPixel( w );
278             h = MMToPixel( h );
279             break;
280 
281         case FL_COORD_POINT :
282             w = PointToPixel( w );
283             h = PointToPixel( h );
284             break;
285 
286         case FL_COORD_centiPOINT :
287             w = CPointToPixel( w );
288             h = CPointToPixel( h );
289             break;
290 
291         case FL_COORD_centiMM :
292             w = CMMToPixel( w );
293             h = CMMToPixel( h );
294             break;
295 
296         default :
297             M_err( "create_new_form", "Unknown unit: %d, using pixel",
298                    fli_cntl.coordUnit );
299             fli_cntl.coordUnit = FL_COORD_PIXEL;
300     }
301 
302     /* Initialize pointers and non-zero defaults */
303 
304     form->w_hr = form->w    = w;
305     form->h_hr = form->h    = h;
306 
307     form->handle_dec_x      = 0;
308     form->handle_dec_y      = 0;
309 
310     form->num_auto_objects  = 0;
311     form->deactivated       = 1;
312     form->form_callback     = NULL;
313     form->compress_mask     =   ExposureMask | ButtonMotionMask
314                               | PointerMotionMask;
315     form->key_callback      = NULL;
316     form->push_callback     = NULL;
317     form->crossing_callback = NULL;
318     form->focusobj          = NULL;
319     form->first             = NULL;
320     form->last              = NULL;
321     form->hotx              = form->hoty = -1;
322     form->use_pixmap        = fli_cntl.doubleBuffer;
323     form->label             = NULL;
324     form->flpixmap          = NULL;
325     form->u_vdata           = NULL;
326     form->close_callback    = NULL;
327     form->close_data        = NULL;
328     form->icon_pixmap       = form->icon_mask = None;
329     form->in_redraw         = 0;
330     form->needs_full_redraw = 1;
331 
332     return form;
333 }
334 
335 
336 /***************************************
337  * Starts a form definition
338  ***************************************/
339 
340 FL_FORM *
fl_bgn_form(int type,FL_Coord w,FL_Coord h)341 fl_bgn_form( int      type,
342              FL_Coord w,
343              FL_Coord h )
344 {
345     if ( ! fli_no_connection && ! flx->display )
346     {
347         M_err( "fl_bgn_form", "Missing or failed call of fl_initialize()" );
348         exit( 1 );
349     }
350 
351     /* Check that we're not already in a form definition - the error is
352        a serious one and can't be fixed easily as it might be due to a
353        bad recursion */
354 
355     if ( fl_current_form )
356     {
357         M_err( "fl_bgn_form", "You forgot to call fl_end_form" );
358         exit( 1 );
359     }
360 
361     /* Create a new form */
362 
363     fl_current_form = create_new_form( w, h );
364 
365     /* Add it to the list of still hidden forms */
366 
367     add_form_to_hidden_list( fl_current_form );
368 
369     /* Each form has an empty box, covering the whole form as its first
370        object */
371 
372     fl_add_box( type, 0, 0, w, h, "" );
373 
374     return fl_current_form;
375 }
376 
377 
378 /***************************************
379  * Ends a form definition
380  ***************************************/
381 
382 void
fl_end_form(void)383 fl_end_form( void )
384 {
385     FL_FORM * f = fl_current_form;
386 
387     if ( ! fl_current_form )
388     {
389         M_err( "fl_end_form", "No current form" );
390         return;
391     }
392 
393     if ( fli_current_group )
394     {
395         M_err( "fl_end_form", "You forgot to call fl_end_group." );
396         fl_end_group( );
397     }
398 
399     fl_current_form = NULL;
400 
401     /* Now is the proper time for calculating the overlaps of objects */
402 
403     fli_recalc_intersections( f );
404 
405     if ( f->visible && ! f->frozen )
406         fl_redraw_form( f );
407 }
408 
409 
410 /***************************************
411  * Reopens a form for adding further objects
412  ***************************************/
413 
414 FL_FORM *
fl_addto_form(FL_FORM * form)415 fl_addto_form( FL_FORM * form )
416 {
417     if ( ! form )
418     {
419         M_err( "fl_addto_form", "NULL form" );
420         return NULL;
421     }
422 
423     /* We can't open a form for adding objects when another form has already
424        been opened for the same purpose */
425 
426     if ( fl_current_form && fl_current_form != form )
427     {
428         M_err( "fl_addto_form", "You forgot to call fl_end_form" );
429         return NULL;
430     }
431 
432     if ( fl_current_form )
433         M_warn( "fl_addto_form", "Form was never closed." );
434 
435     return fl_current_form = form;
436 }
437 
438 
439 /***************************************
440  * Starts a group definition by adding an object of type FL_BEGIN_GROUP
441  ***************************************/
442 
443 FL_OBJECT *
fl_bgn_group(void)444 fl_bgn_group( void )
445 {
446     static int id = 1;
447 
448     if ( ! fl_current_form )
449     {
450         M_err( "fl_bgn_group", "NULL form" );
451         return NULL;
452     }
453 
454     if ( fli_current_group )
455     {
456         M_err( "fl_bgn_group", "You forgot to call fl_end_group." );
457         fl_end_group( );
458     }
459 
460     fli_current_group = fl_make_object( FL_BEGIN_GROUP, 0, 0, 10, 10, 0,
461                                         "", NULL );
462     fli_current_group->group_id = id++;
463 
464     /* Temporarily set the object class to something invalid since
465        fl_add_object() will not add objects of class FL_BEGIN_GROUP */
466 
467     fli_current_group->objclass = FL_INVALID_CLASS;
468     fl_add_object( fl_current_form, fli_current_group );
469     fli_current_group->objclass = FL_BEGIN_GROUP;
470 
471     return fli_current_group;
472 }
473 
474 
475 /***************************************
476  * Ends a group definition by adding an object of type FL_END_GROUP
477  ***************************************/
478 
479 FL_OBJECT *
fli_end_group(void)480 fli_end_group( void )
481 {
482     FL_OBJECT *obj;
483     int id;
484 
485     if ( ! fl_current_form )
486     {
487         M_err( "fl_end_group", "NULL form" );
488         return NULL;
489     }
490 
491     if ( ! fli_current_group )
492     {
493         M_err( "fl_end_group", "NULL group." );
494         return NULL;
495     }
496 
497     obj = fli_current_group;
498     id = obj->group_id;
499     fli_current_group = NULL;
500 
501     if ( ! reopened_group )
502     {
503         obj = fl_make_object( FL_END_GROUP, 0, 0, 0, 0, 0, "", NULL );
504         obj->group_id = id;
505 
506         /* Temporarily set the object class to something invalid since
507            fl_add_object() will not add objects of class FL_END_GROUP */
508 
509         obj->objclass = FL_INVALID_CLASS;
510         fl_add_object( fl_current_form, obj );
511         obj->objclass = FL_END_GROUP;
512     }
513 
514     if ( reopened_group == 2 )
515         fl_end_form( );
516 
517     reopened_group = 0;
518 
519     return obj;
520 }
521 
522 
523 /***************************************
524  * Necessary since the public interface function for ending a group
525  * doesn't have a return value
526  ***************************************/
527 
528 void
fl_end_group(void)529 fl_end_group( void )
530 {
531     fli_end_group( );
532 }
533 
534 
535 /***************************************
536  * "Freezes" all (shown) forms
537  ***************************************/
538 
539 void
fl_freeze_all_forms(void)540 fl_freeze_all_forms( void )
541 {
542     int i;
543 
544     for ( i = 0; i < fli_int.formnumb; i++ )
545         fl_freeze_form( fli_int.forms[ i ] );
546 }
547 
548 
549 /***************************************
550  * "Unfreezes" all (shown) forms
551  ***************************************/
552 
553 void
fl_unfreeze_all_forms(void)554 fl_unfreeze_all_forms( void )
555 {
556     int i;
557 
558     for ( i = 0; i < fli_int.formnumb; i++ )
559         fl_unfreeze_form( fli_int.forms[ i ] );
560 }
561 
562 
563 /***************************************
564  * Corrects the shape of the form based on the shape of its window
565  ***************************************/
566 
567 static void
reshape_form(FL_FORM * form)568 reshape_form( FL_FORM * form )
569 {
570     FL_Coord w,
571              h,
572              dummy;
573     int top,
574         right,
575         bottom,
576         left;
577 
578     if (    ( ! form->handle_dec_x && ! form->handle_dec_y )
579          || form->wm_border == FL_NOBORDER )
580     {
581         fl_get_wingeometry( form->window, &form->x, &form->y, &w, &h );
582         fl_set_form_size( form, w, h );
583         return;
584     }
585 
586     fl_get_decoration_sizes( form, &top, &right, &bottom, &left );
587 
588     if ( form->handle_dec_x && ! form->handle_dec_y )
589     {
590         fl_get_wingeometry( form->window, &dummy, &form->y, &w, &h );
591         form->x -= left;
592     }
593     else if ( ! form->handle_dec_x && form->handle_dec_y )
594     {
595         fl_get_wingeometry( form->window, &form->x, &dummy, &w, &h );
596         form->y -= bottom;
597     }
598     else
599     {
600         fl_get_wingeometry( form->window, &dummy, &dummy, &w, &h );
601         form->x -= left;
602         form->y -= bottom;
603     }
604 
605     XMoveWindow( flx->display, form->window, form->x, form->y );
606     fl_set_form_size( form, w, h );
607 }
608 
609 
610 /***************************************
611  * Scale a form with the given scaling factors and take care of object
612  * gravity. This one differs from fl_scale_form() in that we don't
613  * reshape the window in any way. Most useful as a follow up to a
614  * ConfigureNotify event
615  ***************************************/
616 
617 void
fli_scale_form(FL_FORM * form,double xsc,double ysc)618 fli_scale_form( FL_FORM * form,
619                 double    xsc,
620                 double    ysc )
621 {
622     FL_OBJECT *obj;
623     double neww = form->w_hr * xsc,
624            newh = form->h_hr * ysc;
625 
626     if ( FL_abs( neww - form->w ) < 1 && FL_abs( newh - form->h ) < 1 )
627         return;
628 
629     form->w_hr = neww;
630     form->h_hr = newh;
631 
632     form->w = FL_crnd( neww );
633     form->h = FL_crnd( newh );
634 
635     if ( form->hotx >= 0 || form->hoty >= 0 )
636     {
637         form->hotx = form->hotx * xsc;
638         form->hoty = form->hoty * ysc;
639     }
640 
641     /* Need to handle different resizing request */
642 
643     for ( obj = form->first; obj; obj = obj->next )
644     {
645         double oldw = obj->fl2 - obj->fl1;
646         double oldh = obj->ft2 - obj->ft1;
647 
648         /* Special case to keep the center of gravity of objects that have
649            no gravity set and aren't to be resized */
650 
651         if (    obj->resize == FL_RESIZE_NONE
652              && obj->segravity == FL_NoGravity
653              && obj->nwgravity == FL_NoGravity )
654         {
655             obj->fl1 += ( xsc - 1 ) * ( obj->fl1 + 0.5 * oldw );
656             obj->ft1 += ( ysc - 1 ) * ( obj->ft1 + 0.5 * oldh );
657             obj->fr1 = neww - obj->fl1;
658             obj->fb1 = newh - obj->ft1;
659 
660             obj->fl2 = obj->fl1 + oldw;
661             obj->ft2 = obj->ft1 + oldh;
662             obj->fr2 = neww - obj->fl2;
663             obj->fb2 = newh - obj->ft2;
664         }
665         else
666         {
667             /* In all other cases we recalculate the position of the upper left
668                hand and the lower right hand corner of the object relative to
669                all the borders of the form enclosing it, taking gravity and
670                resizing setting into account. The results sometimes can be
671                unexpected but hopefully are logically correct;-) */
672 
673             if ( ULC_POS_LEFT_FIXED( obj ) )
674                 obj->fr1 = neww - obj->fl1;
675             else if ( ULC_POS_RIGHT_FIXED( obj ) )
676                 obj->fl1 = neww - obj->fr1;
677 
678             if ( LRC_POS_LEFT_FIXED( obj ) )
679                 obj->fr2 = neww - obj->fl2;
680             else if ( LRC_POS_RIGHT_FIXED( obj ) )
681                 obj->fl2 = neww - obj->fr2;
682 
683             if ( ! HAS_FIXED_HORI_ULC_POS( obj ) )
684             {
685                 if ( HAS_FIXED_HORI_LRC_POS( obj ) )
686                 {
687                     if ( obj->resize & FL_RESIZE_X )
688                         obj->fl1 = obj->fl2 - xsc * oldw;
689                     else
690                         obj->fl1 = obj->fl2 - oldw;
691                 }
692                 else
693                     obj->fl1 *= xsc;
694 
695                 obj->fr1 = neww - obj->fl1;
696             }
697 
698             if ( ! HAS_FIXED_HORI_LRC_POS( obj ) )
699             {
700                 if ( obj->resize & FL_RESIZE_X )
701                     obj->fl2 = obj->fl1 + xsc * oldw;
702                 else
703                     obj->fl2 = obj->fl1 + oldw;
704 
705                 obj->fr2 = neww - obj->fl2;
706             }
707 
708             if ( ULC_POS_TOP_FIXED( obj ) )
709                 obj->fb1 = newh - obj->ft1;
710             else if ( ULC_POS_BOTTOM_FIXED( obj ) )
711                 obj->ft1 = newh - obj->fb1;
712 
713             if ( LRC_POS_TOP_FIXED( obj ) )
714                 obj->fb2 = newh - obj->ft2;
715             else if ( LRC_POS_BOTTOM_FIXED( obj ) )
716                 obj->ft2 = newh - obj->fb2;
717 
718             if ( ! HAS_FIXED_VERT_ULC_POS( obj ) )
719             {
720                 if ( HAS_FIXED_VERT_LRC_POS( obj ) )
721                 {
722                     if ( obj->resize & FL_RESIZE_Y )
723                         obj->ft1 = obj->ft2 - ysc * oldh;
724                     else
725                         obj->ft1 = obj->ft2 - oldh;
726                 }
727                 else
728                     obj->ft1 *= ysc;
729 
730                 obj->fb1 = newh - obj->ft1;
731             }
732 
733             if ( ! HAS_FIXED_VERT_LRC_POS( obj ) )
734             {
735                 if ( obj->resize & FL_RESIZE_Y )
736                     obj->ft2 = obj->ft1 + ysc * oldh;
737                 else
738                     obj->ft2 = obj->ft1 + oldh;
739 
740                 obj->fb2 = newh - obj->ft2;
741             }
742         }
743 
744         obj->x = FL_crnd( obj->fl1 );
745         obj->y = FL_crnd( obj->ft1 );
746         obj->w = FL_crnd( obj->fl2 - obj->fl1 );
747         obj->h = FL_crnd( obj->ft2 - obj->ft1 );
748     }
749 
750     /* Only notify objects now - parent objects might have to adjust
751        sizes and positions of child objects and when objects get the
752        resize notice immediately after resizing above then the parent
753        object gets it first, sets a different size for the child, which
754        then is overwritten */
755 
756     for ( obj = form->first; obj; obj = obj->next )
757         fli_handle_object( obj, FL_RESIZED, 0, 0, 0, NULL, 0 );
758 
759     fli_recalc_intersections( form );
760 }
761 
762 
763 /***************************************
764  * Externally visible routine to scale a form. Needs to reshape the window.
765  ***************************************/
766 
767 void
fl_scale_form(FL_FORM * form,double xsc,double ysc)768 fl_scale_form( FL_FORM * form,
769                double    xsc,
770                double    ysc )
771 {
772     if ( ! form )
773     {
774         M_err( "fl_scale_form", "NULL form" );
775         return;
776     }
777 
778     if (    FL_crnd( form->w_hr * xsc ) == form->w
779          && FL_crnd( form->h_hr * ysc ) == form->h )
780         return;
781 
782     fli_scale_form( form, xsc, ysc );
783 
784     /* Resize the window */
785 
786     if ( form->visible == FL_VISIBLE )
787         fl_winresize( form->window, form->w, form->h );
788 }
789 
790 
791 /***************************************
792  * Sets lower limits for the width and height of a form
793  ***************************************/
794 
795 void
fl_set_form_minsize(FL_FORM * form,FL_Coord w,FL_Coord h)796 fl_set_form_minsize( FL_FORM * form,
797                      FL_Coord  w,
798                      FL_Coord  h )
799 {
800     if ( ! form )
801     {
802         M_err( "fl_set_form_minsize", "Null form" );
803         return;
804     }
805 
806     fl_winminsize( form->window, w, h );
807 }
808 
809 
810 /***************************************
811  * Sets upper limits for the width and height of a form
812  ***************************************/
813 
814 void
fl_set_form_maxsize(FL_FORM * form,FL_Coord w,FL_Coord h)815 fl_set_form_maxsize( FL_FORM * form,
816                      FL_Coord  w,
817                      FL_Coord  h )
818 {
819     if ( ! form )
820     {
821         M_err( "fl_set_form_maxsize", "NULL form" );
822         return;
823     }
824 
825     fl_winmaxsize( form->window, w, h );
826 }
827 
828 
829 /***************************************
830  * Switches double buffering for forms on or off (with double buffering
831  * on we draw first to a pixmap for the form before copying that to the
832  * forms window - can reduces flickering)
833  ***************************************/
834 
835 void
fl_set_form_dblbuffer(FL_FORM * form,int yesno)836 fl_set_form_dblbuffer( FL_FORM * form,
837                        int       yesno )
838 {
839     if ( ! form )
840     {
841         M_err( "fl_set_form_dblbuffer", "NULL form" );
842         return;
843     }
844 
845     if ( form->use_pixmap == yesno )
846         return;
847 
848     /* If the form is currently frozen the redraw on unfreeze will only
849        draw those objects that have been changed and thus have their
850        'redraw' flag set. But when switching double buffering on there's
851        no pixmap yet that already contains the non-modified objects. Thus
852        in this case we must make sure all objects of the form get redrawn. */
853 
854     if ( yesno && form->frozen )
855         form->needs_full_redraw = 1;
856 
857     form->use_pixmap = yesno;
858 }
859 
860 
861 /***************************************
862  * Sets the size of a form
863  ***************************************/
864 
865 void
fl_set_form_size(FL_FORM * form,FL_Coord w,FL_Coord h)866 fl_set_form_size( FL_FORM * form,
867                   FL_Coord  w,
868                   FL_Coord  h )
869 {
870     if ( ! form )
871     {
872         M_err( "fl_set_form_size", "NULL form" );
873         return;
874     }
875 
876     if ( w != form->w || h != form->h )
877         fl_scale_form( form, w / form->w_hr, h / form->h_hr );
878 }
879 
880 
881 /***************************************
882  * Sets the position of a form
883  ***************************************/
884 
885 void
fl_set_form_position(FL_FORM * form,FL_Coord x,FL_Coord y)886 fl_set_form_position( FL_FORM * form,
887                       FL_Coord  x,
888                       FL_Coord  y )
889 {
890     FL_Coord oldx,
891              oldy;
892 
893     if ( ! form )
894     {
895         M_err( "fl_set_form_position", "NULL form" );
896         return;
897     }
898 
899     oldx = form->x;
900     oldy = form->y;
901 
902     /* Negative values for x or y are interpreted as meaning that the
903        position is that of the right or bottom side of the form relative
904        to the right or bottom side to the screen. May have to be corrected
905        for the right or bottom border decoration widths. */
906 
907     if ( x >= 0 )
908     {
909         form->x = x;
910         form->handle_dec_x = 0;
911     }
912     else
913     {
914         form->x = fl_scrw - form->w + x;
915         form->handle_dec_x = 1;
916     }
917 
918     if ( y >= 0 )
919     {
920         form->y = y;
921         form->handle_dec_y = 0;
922     }
923     else
924     {
925         form->y = fl_scrh - form->h + y;
926         form->handle_dec_y = 1;
927     }
928 
929     /* If the form is already shown move it */
930 
931     if ( form->visible == FL_VISIBLE )
932     {
933         int bottom = 0,
934             left = 0,
935             dummy;
936 
937         if (    ( form->handle_dec_x || form->handle_dec_y )
938              && form->wm_border != FL_NOBORDER )
939         {
940             fl_get_decoration_sizes( form, &dummy, &dummy, &bottom, &left );
941 
942             if ( form->handle_dec_x )
943                 form->x -= left;
944 
945             if ( form->handle_dec_y )
946                 form->y -= bottom;
947         }
948 
949         form->handle_dec_x = form->handle_dec_y = 0;
950 
951         if ( oldx != form->x || oldy != form->y )
952             XMoveWindow( flx->display, form->window, form->x, form->y );
953     }
954 }
955 
956 
957 /***************************************
958  * Sets the background color of the form - a bit of a hack since it
959  * actually uses the first or second object of the form...
960  ***************************************/
961 
962 void
fl_set_form_background_color(FL_FORM * form,FL_COLOR color)963 fl_set_form_background_color( FL_FORM * form,
964                               FL_COLOR  color )
965 {
966     if ( ! form )
967     {
968         M_err( "fl_set_forms_background_color", "NULL form" );
969         return;
970     }
971 
972     /* If the empty box that all forms get as their first object on creation
973        does not exist anymore we can't set a background color */
974 
975     if ( ! form->first )
976     {
977         M_err( "fl_set_forms_background_color", "Form has no background" );
978         return;
979     }
980 
981     /* If there's no other object except the empty box or the first object
982        isn't an empty box anymore set the color for this first object, otherwise
983        for the next object. */
984 
985     if ( ! form->first->next || form->first->boxtype != FL_NO_BOX )
986         fl_set_object_color( form->first, color, form->first->col2 );
987     else
988         fl_set_object_color( form->first->next, color,
989                              form->first->next->col2 );
990 }
991 
992 
993 /***************************************
994  * Returns the background color used for the form
995  ***************************************/
996 
997 FL_COLOR
fl_get_form_background_color(FL_FORM * form)998 fl_get_form_background_color( FL_FORM * form )
999 {
1000     if ( ! form )
1001     {
1002         M_err( "fl_get_forms_background_color", "NULL form" );
1003         return FL_COL1;
1004     }
1005 
1006     /* If the empty box that all forms get as their first object on creation
1007        does not exist anymore we can't set a background color */
1008 
1009     if ( ! form->first )
1010     {
1011         M_err( "fl_get_forms_background_color", "Form has no background" );
1012         return FL_COL1;
1013     }
1014 
1015     if ( form->first->boxtype != FL_NO_BOX || ! form->first->next )
1016         return form->first->col1;
1017     else
1018         return form->first->next->col1;
1019 }
1020 
1021 
1022 /***************************************
1023  * Sets the position of the hotspot of a form
1024  ***************************************/
1025 
1026 void
fl_set_form_hotspot(FL_FORM * form,FL_Coord x,FL_Coord y)1027 fl_set_form_hotspot( FL_FORM * form,
1028                      FL_Coord  x,
1029                      FL_Coord  y )
1030 {
1031     if ( ! form )
1032     {
1033         M_err( "fl_set_form_hotspot", "NULL form" );
1034         return;
1035     }
1036 
1037     form->hotx = x;
1038     form->hoty = y;
1039 }
1040 
1041 
1042 /***************************************
1043  * Sets the position of the hotspot of a form
1044  * to the center of one of its objects
1045  ***************************************/
1046 
1047 void
fl_set_form_hotobject(FL_FORM * form,FL_OBJECT * obj)1048 fl_set_form_hotobject( FL_FORM   * form,
1049                        FL_OBJECT * obj )
1050 {
1051     if ( ! form  )
1052     {
1053         M_err( "fl_set_form_hotobject", "NULL form" );
1054         return;
1055     }
1056 
1057     if ( ! obj )
1058     {
1059         M_err( "fl_set_form_hotobject", "NULL object" );
1060         return;
1061     }
1062 
1063     if ( obj->form != form )
1064     {
1065         M_err( "fl_set_form_hotobject", "Object not part of form" );
1066         return;
1067     }
1068 
1069     fl_set_form_hotspot( form, obj->x + obj->w / 2, obj->y + obj->h / 2 );
1070 }
1071 
1072 
1073 /***************************************
1074  * Try to make sure a form is completely visible on the screen
1075  ***************************************/
1076 
1077 static void
force_visible(FL_FORM * form)1078 force_visible( FL_FORM * form )
1079 {
1080     if ( form->x > fl_scrw - form->w )
1081         form->x = fl_scrw - form->w;
1082 
1083     if ( form->x < 0 )
1084         form->x = 0;
1085 
1086     if ( form->y > fl_scrh - form->h )
1087         form->y = fl_scrh - form->h;
1088 
1089     if ( form->y < 0 )
1090         form->y = 0;
1091 }
1092 
1093 
1094 /***************************************
1095  * Sets the name (label) of the form. If the form
1096  * is shown it's also the form's window title.
1097  ***************************************/
1098 
1099 void
fl_set_form_title(FL_FORM * form,const char * name)1100 fl_set_form_title( FL_FORM *    form,
1101                    const char * name )
1102 {
1103     if ( ! form )
1104     {
1105         M_err( "fl_set_form_title", "NULL form" );
1106         return;
1107     }
1108 
1109     if ( form->label != name )
1110     {
1111         if ( form->label )
1112             fl_free( form->label );
1113         form->label = fl_strdup( name ? name : "" );
1114     }
1115 
1116     if ( form->window )
1117         fl_wintitle( form->window, form->label );
1118 }
1119 
1120 
1121 /***************************************
1122  * Sets the name (label) of the form using a format string
1123  ***************************************/
1124 
1125 void
fl_set_form_title_f(FL_FORM * form,const char * fmt,...)1126 fl_set_form_title_f( FL_FORM *    form,
1127                      const char * fmt,
1128                      ... )
1129 {
1130     char *buf;
1131 
1132     EXPAND_FORMAT_STRING( buf, fmt );
1133     fl_set_form_title( form, buf );
1134     fl_free( buf );
1135 }
1136 
1137 
1138 /***************************************
1139  * Creates the window for a form (but doesn't show it yet, use
1140  * fl_show_form_window() for that), returns the window handle
1141  ***************************************/
1142 
1143 Window
fl_prepare_form_window(FL_FORM * form,int place,int border,const char * name)1144 fl_prepare_form_window( FL_FORM    * form,
1145                         int          place,
1146                         int          border,
1147                         const char * name )
1148 {
1149     long screenw,
1150          screenh,
1151          dont_fix_size = 0;
1152     FL_Coord mx,
1153              my;
1154 
1155     if ( border == 0 )
1156         border = FL_FULLBORDER;
1157 
1158     if ( fl_current_form )
1159     {
1160         M_err( "fl_prepare_form_window", "You forgot to call fl_end_form() %s",
1161                name ? name : "" );
1162         fl_current_form = NULL;
1163     }
1164 
1165     if ( ! form )
1166     {
1167         M_err( "fl_prepare_form", "NULL form" );
1168         return None;
1169     }
1170 
1171     if ( form->visible != FL_INVISIBLE )
1172         return form->window;
1173 
1174     /* Try to move the form from the part of the list for hidden forms to
1175        that at the start for visible forms */
1176 
1177     move_form_to_visible_list( form );
1178 
1179     if ( form->label != name )
1180     {
1181         if ( form->label )
1182             fl_free( form->label );
1183         form->label = fl_strdup( name ? name : "" );
1184     }
1185 
1186     if ( border == FL_NOBORDER )
1187         fli_int.unmanaged_count++;
1188 
1189     form->wm_border = border;
1190     form->deactivated = 0;
1191     screenw = fl_scrw;
1192     screenh = fl_scrh;
1193 
1194     fl_get_mouse( &mx, &my, &fli_int.keymask );
1195 
1196     if ( ( dont_fix_size = place & FL_FREE_SIZE ) )
1197         place &= ~ FL_FREE_SIZE;
1198 
1199     if ( place == FL_PLACE_SIZE )
1200         fl_pref_winsize( form->w, form->h );
1201     else if ( place == FL_PLACE_ASPECT )
1202         fl_winaspect( 0, form->w, form->h );
1203     else if ( place == FL_PLACE_POSITION )
1204     {
1205         fl_pref_winposition( form->x, form->y );
1206         fl_initial_winsize( form->w, form->h );
1207     }
1208     else if ( place != FL_PLACE_FREE )
1209     {
1210         FL_COORD nmx,
1211                  nmy;
1212 
1213         switch ( place )
1214         {
1215             case FL_PLACE_CENTER:
1216             case FL_PLACE_FREE_CENTER:
1217                 form->x = ( screenw - form->w ) / 2;
1218                 form->y = ( screenh - form->h ) / 2;
1219                 break;
1220 
1221             case FL_PLACE_MOUSE:
1222                 form->x = mx - form->w / 2;
1223                 form->y = my - form->h / 2;
1224                 break;
1225 
1226             case FL_PLACE_FULLSCREEN:
1227                 form->x = 0;
1228                 form->y = 0;
1229                 fl_set_form_size( form, screenw, screenh );
1230                 break;
1231 
1232             case FL_PLACE_HOTSPOT:
1233                 if ( form->hotx < 0 || form->hoty < 0 )    /* not set */
1234                 {
1235                     form->hotx = form->w / 2;
1236                     form->hoty = form->h / 2;
1237                 }
1238 
1239                 form->x = mx - form->hotx;
1240                 form->y = my - form->hoty;
1241 
1242                 force_visible( form );
1243 
1244                 nmx = form->x + form->hotx;
1245                 nmy = form->y + form->hoty;
1246 
1247                 if ( nmx != mx || nmy != my )
1248                     fl_set_mouse( nmx, nmy );
1249 
1250                 break;
1251 
1252             case FL_PLACE_GEOMETRY :
1253                 if ( form->x < 0 )
1254                 {
1255                     form->x = screenw - form->w + form->x;
1256                     form->handle_dec_x = 1;
1257                 }
1258                 if ( form->y < 0 )
1259                 {
1260                     form->y = screenh - form->h + form->y;
1261                     form->handle_dec_y = 1;
1262                 }
1263                 break;
1264         }
1265 
1266         /* Final check. Make sure form is visible */
1267 
1268         if ( place != FL_PLACE_GEOMETRY )
1269             force_visible( form );
1270 
1271         if ( dont_fix_size && place != FL_PLACE_GEOMETRY )
1272             fl_initial_wingeometry( form->x, form->y, form->w, form->h );
1273         else
1274             fl_pref_wingeometry( form->x, form->y, form->w, form->h );
1275     }
1276     else if ( place == FL_PLACE_FREE )
1277     {
1278         fl_initial_winsize( form->w, form->h );
1279         if ( has_initial )
1280             fl_initial_wingeometry( form->x, form->y, form->w, form->h );
1281     }
1282     else
1283     {
1284         M_err( "fl_prepare_form_window", "Unknown requests: %d", place );
1285         fl_initial_wingeometry( form->x, form->y, form->w, form->h );
1286     }
1287 
1288     /* Window managers typically do not allow dragging transient windows */
1289 
1290     if ( border != FL_FULLBORDER )
1291     {
1292         if ( place == FL_PLACE_ASPECT || place == FL_PLACE_FREE )
1293         {
1294             form->x = mx - form->w / 2;
1295             form->y = my - form->h / 2;
1296             force_visible( form );
1297             fl_initial_winposition( form->x, form->y );
1298         }
1299 
1300         if ( border == FL_NOBORDER )
1301             fl_noborder( );
1302         else
1303             fl_transient( );
1304     }
1305 
1306     if ( place == FL_PLACE_ICONIC )
1307         fl_initial_winstate( IconicState );
1308     if ( form->icon_pixmap )
1309         fl_winicon( 0, form->icon_pixmap, form->icon_mask );
1310 
1311     has_initial = 0;
1312     fli_init_colormap( fl_vmode );
1313 
1314     form->window = fli_create_window( fl_root, fli_colormap( fl_vmode ), name );
1315     fl_winicontitle( form->window, name );
1316 
1317     if ( border == FL_FULLBORDER || form->prop & FLI_COMMAND_PROP )
1318         set_form_property( form, FLI_COMMAND_PROP );
1319 
1320     return form->window;
1321 }
1322 
1323 
1324 /***************************************
1325  ***************************************/
1326 
1327 Window
fl_prepare_form_window_f(FL_FORM * form,int place,int border,const char * fmt,...)1328 fl_prepare_form_window_f( FL_FORM    * form,
1329                           int          place,
1330                           int          border,
1331                           const char * fmt,
1332                           ... )
1333 {
1334     Window w;
1335     char *buf;
1336 
1337     EXPAND_FORMAT_STRING( buf, fmt );
1338     w = fl_prepare_form_window( form, place, border, buf );
1339     fl_free( buf );
1340     return w;
1341 }
1342 
1343 
1344 /***************************************
1345  * Maps (displays) a form's window created with fl_prepare_form_window()
1346  ***************************************/
1347 
1348 Window
fl_show_form_window(FL_FORM * form)1349 fl_show_form_window( FL_FORM * form )
1350 {
1351     FL_OBJECT *obj;
1352 
1353     if ( ! form  )
1354     {
1355         M_err( "fl_show_form_window", "NULL form" );
1356         return None;
1357     }
1358 
1359     if ( form->window == None || form->visible != FL_INVISIBLE )
1360         return form->window;
1361 
1362     fl_winshow( form->window );
1363     form->visible = FL_VISIBLE;
1364     reshape_form( form );
1365     fl_redraw_form( form );
1366 
1367     /* TODO: somehow formbrowser objects get drawn incorrectly the first
1368        time round so, for the time being, we redraw it once again... */
1369 
1370     for ( obj = form->first; obj; obj = obj->next )
1371         if ( obj->objclass == FL_FORMBROWSER )
1372             fl_redraw_object( obj );
1373 
1374     /* Check if there's an object we can make the object that has the focus,
1375        it must be an input object and be active and visible */
1376 
1377     if ( ! form->focusobj )
1378         for ( obj = form->first; obj; obj = obj->next )
1379             if ( obj->input && obj->active && obj->visible )
1380             {
1381                 fl_set_focus_object( form, obj );
1382                 break;
1383             }
1384 
1385     return form->window;
1386 }
1387 
1388 
1389 /***************************************
1390  * Makes a new form visible by creating a window for it
1391  * and mapping it. Returns the form's window handle.
1392  ***************************************/
1393 
1394 Window
fl_show_form(FL_FORM * form,int place,int border,const char * name)1395 fl_show_form( FL_FORM *    form,
1396               int          place,
1397               int          border,
1398               const char * name )
1399 {
1400     if ( ! form  )
1401     {
1402         M_err( "fl_show_form", "NULL form" );
1403         return None;
1404     }
1405 
1406     fl_prepare_form_window( form, place, border, name );
1407     form->in_redraw = 0;
1408     return fl_show_form_window( form );
1409 }
1410 
1411 
1412 /***************************************
1413  ***************************************/
1414 
1415 Window
fl_show_form_f(FL_FORM * form,int place,int border,const char * fmt,...)1416 fl_show_form_f( FL_FORM    * form,
1417                 int          place,
1418                 int          border,
1419                 const char * fmt,
1420                 ... )
1421 {
1422     Window w;
1423     char *buf;
1424 
1425     EXPAND_FORMAT_STRING( buf, fmt );
1426     w = fl_show_form( form, place, border, buf );
1427     fl_free( buf );
1428     return w;
1429 }
1430 
1431 
1432 /***************************************
1433  * Hides a particular form by unmapping and destroying its window
1434  ***************************************/
1435 
1436 static void
close_form_window(Window win)1437 close_form_window( Window win )
1438 {
1439     XEvent xev;
1440 
1441     XUnmapWindow( flx->display, win );
1442     XDestroyWindow( flx->display, win );
1443     XSync( flx->display, 0 );
1444 
1445     while ( XCheckWindowEvent( flx->display, win, AllEventsMask, &xev ) )
1446         fli_xevent_name( "Eaten", &xev );
1447 
1448     /* Give subwindows a chance to handle destroy event promptly, take care
1449        the window of the form doesn't exist anymore! */
1450 
1451     while ( XCheckTypedEvent( flx->display, DestroyNotify, &xev ) )
1452     {
1453         FL_FORM *form;
1454 
1455         if ( ( form = fli_find_event_form( &xev ) ) )
1456         {
1457             form->window = None;
1458             fl_hide_form( form );
1459         }
1460         else
1461             fl_XPutBackEvent( &xev );
1462     }
1463 }
1464 
1465 
1466 /***************************************
1467  ***************************************/
1468 
1469 static FL_FORM *
property_set(unsigned int prop)1470 property_set( unsigned int prop )
1471 {
1472     int i;
1473 
1474     for ( i = 0; i < fli_int.formnumb; i++ )
1475         if (    fli_int.forms[ i ]->prop & prop
1476              && fli_int.forms[ i ]->prop & FLI_PROP_SET )
1477             return fli_int.forms[ i ];
1478 
1479     return NULL;
1480 }
1481 
1482 
1483 /***************************************
1484  ***************************************/
1485 
1486 static void
set_form_property(FL_FORM * form,unsigned int prop)1487 set_form_property( FL_FORM *    form,
1488                    unsigned int prop )
1489 {
1490     if ( ! form  )
1491     {
1492         M_err( "set_form_property", "NULL form" );
1493         return;
1494     }
1495 
1496     if ( property_set( prop ) )
1497         return;
1498 
1499     if ( ! ( prop & FLI_COMMAND_PROP ) )
1500     {
1501         M_err( "set_form_property", "Unknown form property request %u",
1502                prop );
1503         return;
1504     }
1505 
1506     if ( form->window )
1507     {
1508         fli_set_winproperty( form->window, FLI_COMMAND_PROP );
1509         form->prop |= FLI_PROP_SET;
1510     }
1511 
1512     form->prop |= FLI_COMMAND_PROP;
1513     fli_mainform = form;
1514 }
1515 
1516 
1517 /***************************************
1518  ***************************************/
1519 
1520 void
fl_hide_form(FL_FORM * form)1521 fl_hide_form( FL_FORM * form )
1522 {
1523     Window owin;
1524     FL_OBJECT *o;
1525 
1526     if ( ! form )
1527     {
1528         M_err( "fl_hide_form", "NULL form" );
1529         return;
1530     }
1531 
1532     if ( fli_get_visible_forms_index( form ) < 0 )
1533     {
1534         M_err( "fl_hide_form", "Hiding unknown form" );
1535         return;
1536     }
1537 
1538     if ( form->visible == FL_BEING_HIDDEN )
1539     {
1540         M_err( "fl_hide_form", "Recursive call?" );
1541         return;
1542     }
1543 
1544     form->visible = FL_BEING_HIDDEN;
1545     fli_set_form_window( form );
1546 
1547     /* Checking mouseobj->form is necessary as it might be deleted from a
1548        form */
1549 
1550     if ( fli_int.mouseobj && fli_int.mouseobj->form == form )
1551     {
1552         fli_handle_object( fli_int.mouseobj, FL_LEAVE, 0, 0, 0, NULL, 1 );
1553         fli_int.mouseobj = NULL;
1554     }
1555 
1556     if ( fli_int.pushobj && fli_int.pushobj->form == form )
1557     {
1558         fli_handle_object( fli_int.pushobj, FL_RELEASE, 0, 0, 0, NULL, 1 );
1559         fli_int.pushobj = NULL;
1560     }
1561 
1562     if ( form->focusobj )
1563     {
1564         fli_handle_object( form->focusobj, FL_UNFOCUS, 0, 0, 0, NULL, 0 );
1565         form->focusobj = NULL;
1566     }
1567 
1568     /* Get canvas objects to unmap their windows (but only for those that
1569        aren't childs, those will be dealt with by their parents) */
1570 
1571     for ( o = form->first; o; o = o->next )
1572         if (    ( o->objclass == FL_CANVAS || o->objclass == FL_GLCANVAS )
1573              && ! o->parent )
1574             fli_unmap_canvas_window( o );
1575 
1576 #ifdef DELAYED_ACTION
1577     fli_object_qflush( form );
1578 #endif
1579 
1580     /* Free backing store pixmap but keep the pointer */
1581 
1582     fli_free_flpixmap( form->flpixmap );
1583 
1584     if ( fli_int.mouseform && fli_int.mouseform->window == form->window )
1585         fli_int.mouseform = NULL;
1586 
1587     form->deactivated = 1;
1588     form->visible = FL_INVISIBLE;
1589     owin = form->window;
1590     form->window = None;
1591 
1592     fli_hide_tooltip( );
1593 
1594     /* If the forms window is None it already has been closed */
1595 
1596     if ( owin )
1597         close_form_window( owin );
1598 
1599     if ( flx->win == owin )
1600         flx->win = None;
1601 
1602     /* Move the form from the part of the list for visible forms to the
1603        part of hidden forms at the end of the array */
1604 
1605     move_form_to_hidden_list( form );
1606 
1607     if ( form->wm_border == FL_NOBORDER )
1608     {
1609         fli_int.unmanaged_count--;
1610         if ( fli_int.unmanaged_count < 0 )
1611         {
1612             M_err( "fl_hide_form", "Bad unmanaged count" );
1613             fli_int.unmanaged_count = 0;
1614         }
1615     }
1616 
1617     /* Need to re-establish command property */
1618 
1619     if ( fli_int.formnumb && form->prop & FLI_COMMAND_PROP )
1620         set_form_property( *fli_int.forms, FLI_COMMAND_PROP );
1621 
1622     if ( form == fli_int.keyform )
1623         fli_int.keyform = NULL;
1624 }
1625 
1626 
1627 /***************************************
1628  * Frees the memory used by a form, together with all its objects.
1629  ***************************************/
1630 
1631 void
fl_free_form(FL_FORM * form)1632 fl_free_form( FL_FORM * form )
1633 {
1634     /* Check whether ok to free */
1635 
1636     if ( ! form )
1637     {
1638         M_err( "fl_free_form", "NULL form" );
1639         return;
1640     }
1641 
1642     if ( form->visible == FL_VISIBLE )
1643     {
1644         M_warn( "fl_free_form", "Freeing visible form" );
1645         fl_hide_form( form );
1646     }
1647 
1648     if ( get_hidden_forms_index( form ) < 0 )
1649     {
1650         M_err( "fl_free_form", "Freeing unknown form" );
1651         return;
1652     }
1653 
1654     /* Free all objects of the form */
1655 
1656     fli_fast_free_object = form;
1657 
1658     while ( form->first )
1659         fl_free_object( form->first );
1660 
1661     fli_fast_free_object = NULL;
1662 
1663     if ( form->flpixmap )
1664     {
1665         fli_free_flpixmap( form->flpixmap );
1666         fl_free( form->flpixmap );
1667     }
1668 
1669     if ( form->label )
1670     {
1671         fl_free( form->label );
1672         form->label = NULL;
1673     }
1674 
1675     if ( form == fli_mainform )
1676         fli_mainform = NULL;
1677 
1678     /* Free the form and remove it from the list of existing forms */
1679 
1680     fl_free( form );
1681 
1682     remove_form_from_hidden_list( form );
1683 }
1684 
1685 
1686 /***************************************
1687  * Returns if a form is active
1688  ***************************************/
1689 
1690 int
fl_form_is_activated(FL_FORM * form)1691 fl_form_is_activated( FL_FORM * form )
1692 {
1693     if ( ! form )
1694     {
1695         M_err( "fl_form_is_activated", "NULL form" );
1696         return 0;
1697     }
1698 
1699     return form->deactivated == 0;
1700 }
1701 
1702 
1703 /***************************************
1704  * Activates a form (form only becomes activated if this function has
1705  * been called as many times as fl_deactive_form()).
1706  ***************************************/
1707 
1708 void
fl_activate_form(FL_FORM * form)1709 fl_activate_form( FL_FORM * form )
1710 {
1711     if ( ! form )
1712     {
1713         M_err( "fl_activate_form", "NULL form" );
1714         return;
1715     }
1716 
1717     if ( form->deactivated )
1718     {
1719         form->deactivated--;
1720 
1721         if ( ! form->deactivated && form->activate_callback )
1722             form->activate_callback( form, form->activate_data );
1723     }
1724 
1725     if ( form->child )
1726         fl_activate_form( form->child );
1727 }
1728 
1729 
1730 /***************************************
1731  * Deactivates a form (re-activation requires as many calls of
1732  * fl_activate_form() as there were calls of fl_deactivate_form()).
1733  ***************************************/
1734 
1735 void
fl_deactivate_form(FL_FORM * form)1736 fl_deactivate_form( FL_FORM * form )
1737 {
1738     if ( ! form )
1739     {
1740         M_err( "fl_deactivate_form", "NULL form" );
1741         return;
1742     }
1743 
1744     if (    ! form->deactivated
1745          && fli_int.mouseobj
1746          && fli_int.mouseobj->form == form )
1747         fli_handle_object( fli_int.mouseobj, FL_LEAVE, 0, 0, 0, NULL, 1 );
1748 
1749     if ( ! form->deactivated && form->deactivate_callback )
1750         form->deactivate_callback( form, form->deactivate_data );
1751 
1752     form->deactivated++;
1753 
1754     if ( form->child )
1755         fl_deactivate_form( form->child );
1756 }
1757 
1758 
1759 /***************************************
1760  * Installs handler to be called on (final) re-activation of the form
1761  ***************************************/
1762 
1763 FL_FORM_ATACTIVATE
fl_set_form_atactivate(FL_FORM * form,FL_FORM_ATACTIVATE cb,void * data)1764 fl_set_form_atactivate( FL_FORM            * form,
1765                         FL_FORM_ATACTIVATE   cb,
1766                         void *               data )
1767 {
1768     FL_FORM_ATACTIVATE old = NULL;
1769 
1770     if ( ! form  )
1771     {
1772         M_err( "fl_set_form_atactivate", "NULL form" );
1773         return NULL;
1774     }
1775 
1776     old = form->activate_callback;
1777     form->activate_callback = cb;
1778     form->activate_data = data;
1779 
1780     return old;
1781 }
1782 
1783 
1784 /***************************************
1785  * Installs handler to be called on (first) deactivation of the form
1786  ***************************************/
1787 
1788 FL_FORM_ATDEACTIVATE
fl_set_form_atdeactivate(FL_FORM * form,FL_FORM_ATDEACTIVATE cb,void * data)1789 fl_set_form_atdeactivate( FL_FORM              * form,
1790                           FL_FORM_ATDEACTIVATE   cb,
1791                           void                 * data )
1792 {
1793     FL_FORM_ATDEACTIVATE old = NULL;
1794 
1795     if ( ! form  )
1796     {
1797         M_err( "fl_set_form_atdeactivate", "NULL form" );
1798         return NULL;
1799     }
1800 
1801     old = form->deactivate_callback;
1802     form->deactivate_callback = cb;
1803     form->deactivate_data = data;
1804 
1805     return old;
1806 }
1807 
1808 
1809 /***************************************
1810  * Activates all forms
1811  ***************************************/
1812 
1813 void
fl_activate_all_forms(void)1814 fl_activate_all_forms( void )
1815 {
1816     int i;
1817 
1818     for ( i = 0; i < fli_int.formnumb; i++ )
1819         fl_activate_form( fli_int.forms[ i ] );
1820 }
1821 
1822 
1823 /***************************************
1824  * Deactivates all forms
1825  ***************************************/
1826 
1827 void
fl_deactivate_all_forms(void)1828 fl_deactivate_all_forms( void )
1829 {
1830     int i;
1831 
1832     for ( i = 0; i < fli_int.formnumb; i++ )
1833         fl_deactivate_form( fli_int.forms[ i ] );
1834 }
1835 
1836 
1837 /***************************************
1838  * Installs handler to be called on close of the form
1839  ***************************************/
1840 
1841 FL_FORM_ATCLOSE
fl_set_form_atclose(FL_FORM * form,FL_FORM_ATCLOSE fmclose,void * data)1842 fl_set_form_atclose( FL_FORM         * form,
1843                      FL_FORM_ATCLOSE   fmclose,
1844                      void            * data )
1845 {
1846     FL_FORM_ATCLOSE old;
1847 
1848     if ( ! form  )
1849     {
1850         M_err( "fl_set_form_atclose", "NULL form" );
1851         return NULL;
1852     }
1853 
1854     old = form->close_callback;
1855     form->close_callback = fmclose;
1856     form->close_data = data;
1857 
1858     return old;
1859 }
1860 
1861 
1862 /***************************************
1863  * Installs handler to be called on end of application by the user
1864  * using some window manager method to close a window
1865  ***************************************/
1866 
1867 FL_FORM_ATCLOSE
fl_set_atclose(FL_FORM_ATCLOSE fmclose,void * data)1868 fl_set_atclose( FL_FORM_ATCLOSE   fmclose,
1869                 void            * data )
1870 {
1871     FL_FORM_ATCLOSE old = fli_context->atclose;
1872 
1873     fli_context->atclose = fmclose;
1874     fli_context->close_data = data;
1875 
1876     return old;
1877 }
1878 
1879 
1880 /***************************************
1881  ***************************************/
1882 
1883 void
fl_set_form_geometry(FL_FORM * form,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)1884 fl_set_form_geometry( FL_FORM  * form,
1885                       FL_Coord   x,
1886                       FL_Coord   y,
1887                       FL_Coord   w,
1888                       FL_Coord   h )
1889 {
1890     fl_set_form_position( form, x, y );
1891     fl_set_form_size( form, w, h );
1892 
1893     /* This alters the windowing defaults */
1894 
1895     fl_initial_wingeometry( form->x, form->y, form->w, form->h );
1896     has_initial = 1;
1897 }
1898 
1899 
1900 /***************************************
1901  * Register pre-emptive event handlers
1902  ***************************************/
1903 
1904 FL_RAW_CALLBACK
fl_register_raw_callback(FL_FORM * form,unsigned long mask,FL_RAW_CALLBACK rcb)1905 fl_register_raw_callback( FL_FORM         * form,
1906                           unsigned long     mask,
1907                           FL_RAW_CALLBACK   rcb )
1908 {
1909     FL_RAW_CALLBACK old_rcb = NULL;
1910     int valid = 0;
1911 
1912     if ( ! form )
1913     {
1914         M_err( "fl_register_raw_callback", "Null form" );
1915         return NULL;
1916     }
1917 
1918     if ( ( mask & FL_ALL_EVENT ) == FL_ALL_EVENT )
1919     {
1920         old_rcb = form->all_callback;
1921         form->evmask = mask;
1922         form->all_callback = rcb;
1923         return old_rcb;
1924     }
1925 
1926     if ( mask & ( KeyPressMask | KeyReleaseMask ) )
1927     {
1928         form->evmask |= mask & ( KeyPressMask | KeyReleaseMask );
1929         old_rcb = form->key_callback;
1930         form->key_callback = rcb;
1931         valid = 1;
1932     }
1933 
1934     if ( mask & ( ButtonPressMask | ButtonReleaseMask ) )
1935     {
1936         form->evmask |= mask & ( ButtonPressMask | ButtonReleaseMask );
1937         old_rcb = form->push_callback;
1938         form->push_callback = rcb;
1939         valid = 1;
1940     }
1941 
1942     if ( mask & ( EnterWindowMask | LeaveWindowMask ) )
1943     {
1944         form->evmask |= mask & ( EnterWindowMask | LeaveWindowMask );
1945         old_rcb = form->crossing_callback;
1946         form->crossing_callback = rcb;
1947         valid = 1;
1948     }
1949 
1950     if ( mask & ( ButtonMotionMask | PointerMotionMask ) )
1951     {
1952         form->evmask |= mask & ( ButtonMotionMask | PointerMotionMask );
1953         old_rcb = form->motion_callback;
1954         form->motion_callback = rcb;
1955         valid = 1;
1956     }
1957 
1958     if ( ! valid )          /* unsupported mask */
1959         M_err( "fl_register_raw_callback", "Unsupported mask 0x%x", mask );
1960 
1961     return old_rcb;
1962 }
1963 
1964 
1965 /***************************************
1966  ***************************************/
1967 
1968 void
fl_set_form_event_cmask(FL_FORM * form,unsigned long cmask)1969 fl_set_form_event_cmask( FL_FORM *     form,
1970                          unsigned long cmask )
1971 {
1972     if ( form )
1973         form->compress_mask = cmask;
1974 }
1975 
1976 
1977 /***************************************
1978  ***************************************/
1979 
1980 unsigned long
fl_get_form_event_cmask(FL_FORM * form)1981 fl_get_form_event_cmask( FL_FORM * form )
1982 {
1983     return form ? form->compress_mask : 0UL;
1984 }
1985 
1986 
1987 /***************************************
1988  * Sets the callback routine for the form
1989  ***************************************/
1990 
1991 void
fl_set_form_callback(FL_FORM * form,FL_FORMCALLBACKPTR callback,void * d)1992 fl_set_form_callback( FL_FORM            * form,
1993                       FL_FORMCALLBACKPTR   callback,
1994                       void *               d )
1995 {
1996     if ( ! form )
1997     {
1998         M_err( "fl_set_form_callback", "NULL form" );
1999         return;
2000     }
2001 
2002     form->form_callback = callback;
2003     form->form_cb_data = d;
2004 }
2005 
2006 
2007 /***************************************
2008  ***************************************/
2009 
2010 void
fl_set_form_icon(FL_FORM * form,Pixmap p,Pixmap m)2011 fl_set_form_icon( FL_FORM * form,
2012                   Pixmap    p,
2013                   Pixmap    m )
2014 {
2015     if ( ! form )
2016         return;
2017 
2018     form->icon_pixmap = p;
2019     form->icon_mask = m;
2020     if ( form->window )
2021         fl_winicon( form->window, p, m );
2022 }
2023 
2024 
2025 /***************************************
2026  ***************************************/
2027 
2028 void
fl_set_app_mainform(FL_FORM * form)2029 fl_set_app_mainform( FL_FORM * form )
2030 {
2031     fli_mainform = form;
2032     set_form_property( form, FLI_COMMAND_PROP );
2033 }
2034 
2035 
2036 /***************************************
2037  ***************************************/
2038 
2039 FL_FORM *
fl_get_app_mainform(void)2040 fl_get_app_mainform( void )
2041 {
2042     return nomainform ? NULL : fli_mainform;
2043 }
2044 
2045 
2046 /***************************************
2047  ***************************************/
2048 
2049 void
fl_set_app_nomainform(int flag)2050 fl_set_app_nomainform( int flag )
2051 {
2052     nomainform = flag;
2053 }
2054 
2055 
2056 /***************************************
2057  * Does a rescale of a form without taking into
2058  * account object gravity or resize settings
2059  ***************************************/
2060 
2061 static void
simple_form_rescale(FL_FORM * form,double scale)2062 simple_form_rescale( FL_FORM * form,
2063                      double    scale )
2064 {
2065     FL_OBJECT *obj;
2066 
2067     form->w_hr *= scale;
2068     form->h_hr *= scale;
2069 
2070     form->w = FL_crnd( form->w_hr );
2071     form->h = FL_crnd( form->h_hr );
2072 
2073     for ( obj = form->first; obj; obj = obj->next )
2074         if ( obj->objclass != FL_BEGIN_GROUP && obj->objclass != FL_END_GROUP )
2075             fli_scale_object( obj, scale, scale );
2076 
2077     fli_recalc_intersections( form );
2078 
2079     fl_redraw_form( form );
2080 }
2081 
2082 
2083 /***************************************
2084  * Checks if the label of an object fits into it (after x- and
2085  * y-margin have been added). If not, all objects and the form
2086  * are enlarged by the necessary factor (but never by more than
2087  * a factor of 1.5).
2088  ***************************************/
2089 
2090 void
fl_fit_object_label(FL_OBJECT * obj,FL_Coord xmargin,FL_Coord ymargin)2091 fl_fit_object_label( FL_OBJECT * obj,
2092                      FL_Coord    xmargin,
2093                      FL_Coord    ymargin )
2094 {
2095     int sw,
2096         sh,
2097         osize,
2098         bw;
2099     double factor,
2100            xfactor,
2101            yfactor;
2102 
2103     if ( fli_no_connection )
2104         return;
2105 
2106     if (    fl_is_outside_lalign( obj->align )
2107          || obj->type == FL_BEGIN_GROUP
2108          || obj->type == FL_END_GROUP
2109          || obj->parent
2110          || ! obj->label
2111          || ! *obj->label
2112          || *obj->label == '@' )
2113         return;
2114 
2115     fl_get_string_dimension( obj->lstyle, obj->lsize, obj->label,
2116                              strlen( obj->label ), &sw, &sh );
2117 
2118     bw = (    obj->boxtype == FL_UP_BOX
2119            || obj->boxtype == FL_DOWN_BOX
2120            || obj->boxtype == FL_EMBOSSED_BOX ) ?
2121         FL_abs( obj->bw ) : 1;
2122 
2123     if (    obj->boxtype == FL_EMBOSSED_BOX )
2124         bw += bw > 2 ? bw - 2 : 1;
2125 
2126     if (    obj->objclass == FL_BUTTON
2127           && (    obj->type == FL_RETURN_BUTTON
2128                || obj->type == FL_MENU_BUTTON ) )
2129         sw += FL_min( 0.6 * obj->h, 0.6 * obj->w ) - 1;
2130 
2131     if ( obj->objclass == FL_BUTTON && obj->type == FL_LIGHTBUTTON )
2132         sw += FL_LIGHTBUTTON_MINSIZE + 1;
2133 
2134     if (    sw <= obj->w - 2 * ( bw + xmargin )
2135          && sh <= obj->h - 2 * ( bw + ymargin ) )
2136         return;
2137 
2138     if ( ( osize = obj->w - 2 * ( bw + xmargin ) ) <= 0 )
2139         osize = 1;
2140     xfactor = ( double ) sw / osize;
2141 
2142     if ( ( osize = obj->h - 2 * ( bw + ymargin ) ) <= 0 )
2143         osize = 1;
2144     yfactor = ( double ) sh / osize;
2145 
2146     factor = FL_max( xfactor, yfactor );
2147 
2148     factor = FL_clamp( factor, 1.0, 1.5 );
2149 
2150     /* Scale all objects without taking care of gravity etc. */
2151 
2152     if ( factor > 1.0 )
2153         simple_form_rescale( obj->form, factor );
2154 }
2155 
2156 
2157 /***************************************
2158  ***************************************/
2159 
2160 void
fli_recount_auto_objects(void)2161 fli_recount_auto_objects( void )
2162 {
2163     int i;
2164 
2165     for ( fli_int.auto_count = i = 0; i < fli_int.formnumb; i++ )
2166         if ( fli_int.forms[ i ]->num_auto_objects > 0 )
2167             fli_int.auto_count++;
2168 }
2169 
2170 
2171 /***************************************
2172  * Reopens a group to allow addition of further objects
2173  ***************************************/
2174 
2175 FL_OBJECT *
fl_addto_group(FL_OBJECT * group)2176 fl_addto_group( FL_OBJECT * group )
2177 {
2178     if ( ! group )
2179     {
2180         M_err( "fl_addto_group", "NULL group." );
2181         return NULL;
2182     }
2183 
2184     if ( group->objclass != FL_BEGIN_GROUP )
2185     {
2186         M_err( "fl_addto_group", "Parameter is not a group object." );
2187         return NULL;
2188     }
2189 
2190     if ( fl_current_form && fl_current_form != group->form )
2191     {
2192         M_err( "fl_addto_group",
2193                "Can't switch to a group on a different form" );
2194         return NULL;
2195     }
2196 
2197     if ( fli_current_group && fli_current_group != group )
2198     {
2199         M_err( "fl_addto_group", "You forgot to call fl_end_group" );
2200         return NULL;
2201     }
2202 
2203     if ( fli_current_group )
2204         M_warn( "fl_addto_group", "Group was never closed" );
2205 
2206     reopened_group = fl_current_form ? 1 : 2;
2207     fl_current_form = group->form;
2208     return fli_current_group = group;
2209 }
2210 
2211 
2212 /***************************************
2213  * Returns if a form is visible
2214  ***************************************/
2215 
2216 int
fl_form_is_visible(FL_FORM * form)2217 fl_form_is_visible( FL_FORM * form )
2218 {
2219     if ( ! form )
2220     {
2221         M_warn( "fl_form_is_visible", "NULL form" );
2222         return FL_INVISIBLE;
2223     }
2224 
2225     return form->window ? form->visible : FL_INVISIBLE;
2226 }
2227 
2228 
2229 /***************************************
2230  * Similar to fit_object_label(), but will do it for all objects and
2231  * has a smaller maximum magnification factor (1.25 instead of 1.5).
2232  * Mainly intended for compensation for font size variations.
2233  ***************************************/
2234 
2235 double
fl_adjust_form_size(FL_FORM * form)2236 fl_adjust_form_size( FL_FORM * form )
2237 {
2238     FL_OBJECT * obj;
2239     double xfactor,
2240            yfactor,
2241            max_factor,
2242            factor;
2243     int sw,
2244         sh,
2245         osize,
2246         bw;
2247 
2248     if ( fli_no_connection )
2249         return 1.0;
2250 
2251     max_factor = factor = 1.0;
2252     for ( obj = form->first; obj; obj = obj->next )
2253     {
2254         if (    fl_is_outside_lalign( obj->align )
2255              || obj->type == FL_BEGIN_GROUP
2256              || obj->type == FL_END_GROUP
2257              || obj->parent
2258              || ! obj->label
2259              || ! *obj->label
2260              || *obj->label == '@' )
2261             continue;
2262 
2263         fl_get_string_dimension( obj->lstyle, obj->lsize, obj->label,
2264                                  strlen( obj->label ), &sw, &sh );
2265 
2266         bw = (    obj->boxtype == FL_UP_BOX
2267                || obj->boxtype == FL_DOWN_BOX
2268                || obj->boxtype == FL_EMBOSSED_BOX ) ?
2269              FL_abs( obj->bw ) : 1;
2270 
2271         if (    obj->boxtype == FL_EMBOSSED_BOX )
2272             bw += bw > 2 ? bw - 2 : 1;
2273 
2274         if (    obj->objclass == FL_BUTTON
2275              && (    obj->type == FL_RETURN_BUTTON
2276                   || obj->type == FL_MENU_BUTTON ) )
2277             sw += FL_min( 0.6 * obj->h, 0.6 * obj->w ) - 1;
2278 
2279         if ( obj->objclass == FL_BUTTON && obj->type == FL_LIGHTBUTTON )
2280             sw += FL_LIGHTBUTTON_MINSIZE + 1;
2281 
2282         if (    sw <= obj->w - 2 * ( bw + 1 )
2283              && sh <= obj->h - 2 * ( bw + 1 ))
2284             continue;
2285 
2286         if ( ( osize = obj->w - 2 * ( bw + 1 ) ) <= 0 )
2287             osize = 1;
2288         xfactor = ( double ) sw / osize;
2289 
2290         if ( ( osize = obj->h - 2 * ( bw + 1 ) ) <= 0 )
2291             osize = 1;
2292         yfactor = ( double ) sh / osize;
2293 
2294         if ( ( factor = FL_max( xfactor, yfactor ) ) > max_factor )
2295             max_factor = factor;
2296     }
2297 
2298     /* Don't scale down and don't scale up by more than a factor of 1.25 */
2299 
2300     max_factor = FL_clamp( max_factor, 1.0, 1.25 );
2301 
2302     /* Scale all objects without taking care of gravity etc. */
2303 
2304     if ( max_factor > 1.0 )
2305         simple_form_rescale( form, max_factor );
2306 
2307     return max_factor;
2308 }
2309 
2310 
2311 /***************************************
2312  ***************************************/
2313 
2314 void
fl_raise_form(FL_FORM * form)2315 fl_raise_form( FL_FORM * form )
2316 {
2317     if ( form && form->window )
2318         XRaiseWindow( fl_display, form->window );
2319     else
2320         M_err( "fl_raise_form", "NULL form or form window not shown" );
2321 }
2322 
2323 
2324 /***************************************
2325  ***************************************/
2326 
2327 void
fl_lower_form(FL_FORM * form)2328 fl_lower_form( FL_FORM * form )
2329 {
2330     if ( form && form->window )
2331         XLowerWindow( fl_display, form->window );
2332     else
2333         M_err( "fl_lower_form", "NULL form or forn window not shown" );
2334 }
2335 
2336 
2337 /***************************************
2338  * Returns the sizes of the "decorations" the window manager puts around
2339  * a forms window. Returns 0 on success and 1 if the form isn't visible
2340  * or it's a form embedded into another form.
2341  * This tries to use the "_NET_FRAME_EXTENTS" atom which resonably recent
2342  * window managers in principle should set. For those window managers that
2343  * don't have that atom we try it with the old trick of searching up for
2344  * the enclosing parent window and using the geometry of this window (but
2345  * note: this doesn't work with window managers that don't reparent the
2346  * windows they manage, and we can't recognize that).
2347  ***************************************/
2348 
2349 int
fl_get_decoration_sizes(FL_FORM * form,int * top,int * right,int * bottom,int * left)2350 fl_get_decoration_sizes( FL_FORM * form,
2351                          int     * top,
2352                          int     * right,
2353                          int     * bottom,
2354                          int     * left )
2355 {
2356     Atom a;
2357 
2358     if (    ! form
2359          || ! form->window
2360          || form->visible != FL_VISIBLE
2361          || form->parent )
2362         return 1;
2363 
2364     /* If the window manager knows about the '_NET_FRAME_EXTENTS' atom ask
2365        for the settings for the forms window, otherwise try by looking for
2366        the size of the enclosing parent window */
2367 
2368     if ( ( a = XInternAtom( fl_get_display( ), "_NET_FRAME_EXTENTS", True ) )
2369                                                                       != None )
2370         get_decoration_sizes_from_wm( a, form, top, right, bottom, left );
2371     else
2372         get_decorations_sizes_from_parent( form, top, right, bottom, left );
2373 
2374     return 0;
2375 }
2376 
2377 
2378 /***************************************
2379  * Gets the decorations sizes via the _NET_FRAME_EXTENTS atom.
2380  ***************************************/
2381 
2382 static
2383 void
get_decoration_sizes_from_wm(Atom a,FL_FORM * form,int * top,int * right,int * bottom,int * left)2384 get_decoration_sizes_from_wm( Atom      a,
2385                               FL_FORM * form,
2386                               int     * top,
2387                               int     * right,
2388                               int     * bottom,
2389                               int     * left )
2390 {
2391     Atom actual_type;
2392     int actual_format;
2393     unsigned long nitems;
2394     unsigned long bytes_after;
2395     static unsigned char *prop;
2396 
2397     XGetWindowProperty( fl_get_display( ), form->window, a, 0,
2398                         4, False, XA_CARDINAL,
2399                         &actual_type, &actual_format, &nitems,
2400                         &bytes_after, &prop );
2401 
2402     /* If no properties are returne the window probably has no decorations */
2403 
2404     if (    actual_type == XA_CARDINAL
2405          && actual_format == 32
2406          && nitems == 4 )
2407     {
2408         *top    = ( ( long * ) prop )[ 2 ];
2409         *right  = ( ( long * ) prop )[ 1 ];
2410         *bottom = ( ( long * ) prop )[ 3 ];
2411         *left   = ( ( long * ) prop )[ 0 ];
2412     }
2413     else
2414         *top = *right =*bottom = *left = 0;
2415 }
2416 
2417 
2418 /***************************************
2419  * Tries to get the size of the decorations of a form the traditional
2420  * way, asuming that the form window is the child of a parent window
2421  * that encloses also the decoration windows (assuming that the window
2422  * manager reparents the windows it manages, otherwise we'll report
2423  * back zero sized decorations without any chance of figuring out that
2424  * this is wrong;-(
2425  ***************************************/
2426 
2427 static
2428 void
get_decorations_sizes_from_parent(FL_FORM * form,int * top,int * right,int * bottom,int * left)2429 get_decorations_sizes_from_parent( FL_FORM * form,
2430                                    int     * top,
2431                                    int     * right,
2432                                    int     * bottom,
2433                                    int     * left )
2434 {
2435     Window cur_win = form->window;
2436     Window root;
2437     Window parent;
2438     Window *childs = NULL;
2439     XWindowAttributes win_attr;
2440     XWindowAttributes frame_attr;
2441     Window wdummy;
2442     unsigned int udummy;
2443 
2444     /* Get the coordinates and size of the form's window */
2445 
2446     XGetWindowAttributes( fl_get_display( ), cur_win, &win_attr );
2447 
2448     /* Try to get its parent window */
2449 
2450     XQueryTree( fl_get_display( ), cur_win, &root, &parent, &childs,
2451                 &udummy );
2452 
2453     /* Childs aren't used, get rid of them */
2454 
2455     if ( childs )
2456     {
2457         XFree( childs );
2458         childs = NULL;
2459     }
2460 
2461     /* If there's no parent or the parent window is the root window
2462        we've got to assume that there are no decorations */
2463 
2464     if ( ! parent || parent == root )
2465     {
2466         *top = *right =*bottom = *left = 0;
2467         return;
2468     }
2469 
2470     /* Now translate the form window's coordiates (that are relative to
2471        its parent) to that relative to the root window and then find the
2472        top-most parent that isn't the root window itself */
2473 
2474     XTranslateCoordinates( fl_get_display( ), parent, root,
2475                            win_attr.x, win_attr.y,
2476                            &win_attr.x, &win_attr.y, &wdummy );
2477 
2478     while ( parent && parent != root )
2479     {
2480         cur_win = parent;
2481         XQueryTree( fl_get_display( ), cur_win, &root, &parent, &childs,
2482                     &udummy );
2483 
2484         if ( childs )
2485         {
2486             XFree( childs );
2487             childs = NULL;
2488         }
2489     }
2490 
2491     /* Get the cordinates and sizes of the top-most window... */
2492 
2493     XGetWindowAttributes( fl_get_display( ), cur_win, &frame_attr );
2494 
2495     /* ...and finally calculate the decoration sizes */
2496 
2497     *top    = win_attr.y - frame_attr.y;
2498     *left   = win_attr.x - frame_attr.x;
2499     *bottom = frame_attr.height - win_attr.height - *top;
2500     *right  = frame_attr.width  - win_attr.width  - *left;
2501 }
2502 
2503 
2504 /***************************************
2505  * Returns if a form window is in iconified state
2506  ***************************************/
2507 
2508 int
fl_form_is_iconified(FL_FORM * form)2509 fl_form_is_iconified( FL_FORM * form )
2510 {
2511     XWindowAttributes xwa;
2512 
2513     if ( ! form )
2514     {
2515         M_err( "fl_form_is_iconified", "NULL form" );
2516         return 0;
2517     }
2518 
2519     if ( ! form->window || form->visible == FL_INVISIBLE )
2520         return 0;
2521 
2522     XGetWindowAttributes( fl_get_display( ), form->window, &xwa );
2523 
2524     return xwa.map_state != IsViewable;
2525 }
2526 
2527 
2528 /*
2529  * Local variables:
2530  * tab-width: 4
2531  * indent-tabs-mode: nil
2532  * End:
2533  */
2534