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