1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "gdrawP.h"
31 #include "ggadget.h"
32 #include "ggadgetP.h"
33 #include "gkeysym.h"
34 #include "gresource.h"
35 #include "gwidgetP.h"
36 #include "utype.h"
37 
38 static GWindow current_focus_window, previous_focus_window, last_input_window;
39     /* in focus follows pointer mode, the current focus doesn't really count */
40     /*  until the window gets input (otherwise moving the mouse across a wind */
41     /*  would set the previous_focus_window to something inappropriate) */
42     /* So... we set current focus window when a window gains the focus, and */
43     /*  at the same time we set the previous focus window to the last window */
44     /*  that got input. NOT to the old current_focus_window (which might be junk) */
45 static GWindow last_paletted_focus_window = NULL;
46 
47 static int broken_palettes = true;
48 static int widgets_initted = false;
49 
gwidget_init(void)50 static void gwidget_init(void) {
51     broken_palettes = GResourceFindBool("GWidget.BrokenPalettes",broken_palettes);
52     widgets_initted = true;
53 }
54 
GWindowGetCurrentFocusTopWindow(void)55 GWindow GWindowGetCurrentFocusTopWindow(void) {
56 return( current_focus_window );
57 }
58 
GWidgetGetPreviousFocusTopWindow(void)59 GWindow GWidgetGetPreviousFocusTopWindow(void) {
60 return( previous_focus_window );
61 }
62 
GWindowGetCurrentFocusGadget(void)63 GGadget *GWindowGetCurrentFocusGadget(void) {
64     GTopLevelD *td;
65     if ( current_focus_window==NULL )
66 return( NULL );
67     td = (GTopLevelD *) (current_focus_window->widget_data);
68 return( td->gfocus );
69 }
70 
GWindowClearFocusGadgetOfWindow(GWindow gw)71 void GWindowClearFocusGadgetOfWindow(GWindow gw) {
72     GTopLevelD *td;
73     if ( gw==NULL )
74 return;
75     while ( gw->parent!=NULL && !gw->is_toplevel ) gw=gw->parent;
76     td = (GTopLevelD *) (gw->widget_data);
77     if ( gw == current_focus_window && td->gfocus!=NULL &&
78 	    td->gfocus->funcs->handle_focus!=NULL ) {
79 	GEvent e;
80 	e.type = et_focus;
81 	e.w = gw;
82 	e.u.focus.gained_focus = false;
83 	e.u.focus.mnemonic_focus = mf_normal;
84 	(td->gfocus->funcs->handle_focus)(td->gfocus,&e);
85     }
86     td->gfocus = NULL;
87 }
88 
GWindowGetFocusGadgetOfWindow(GWindow gw)89 GGadget *GWindowGetFocusGadgetOfWindow(GWindow gw) {
90     GTopLevelD *td;
91     if ( gw==NULL )
92 return( NULL );
93     while ( gw->parent!=NULL && !gw->is_toplevel ) gw=gw->parent;
94     td = (GTopLevelD *) (gw->widget_data);
95 return( td->gfocus );
96 }
97 
GGadgetActiveGadgetEditCmd(GWindow gw,enum editor_commands cmd)98 int GGadgetActiveGadgetEditCmd(GWindow gw,enum editor_commands cmd) {
99     GGadget *g = GWindowGetFocusGadgetOfWindow(gw);
100 
101     if ( g==NULL )
102 return( false );
103 return( GGadgetEditCmd(g,cmd));
104 }
105 
GWidgetGetCurrentFocusWindow(void)106 GWindow GWidgetGetCurrentFocusWindow(void) {
107     GTopLevelD *td;
108     if ( current_focus_window==NULL )
109 return( NULL );
110     td = (GTopLevelD *) (current_focus_window->widget_data);
111     if ( td->gfocus!=NULL )
112 return( td->gfocus->base );
113     return NULL;
114 }
115 
116 struct gfuncs *last_indicatedfocus_funcs;		/* !!!! Debug code */
117 GGadget *last_indicatedfocus_gadget;
118 struct gwindow *last_indicatedfocus_widget;
119 
_GWidget_IndicateFocusGadget(GGadget * g,enum mnemonic_focus mf)120 static void _GWidget_IndicateFocusGadget(GGadget *g, enum mnemonic_focus mf) {
121     GWindow top;
122     GTopLevelD *td;
123     GEvent e;
124 
125   last_indicatedfocus_funcs = g->funcs;
126   last_indicatedfocus_gadget = g;
127   last_indicatedfocus_widget = g->base;
128 
129     if ( g->funcs==NULL ) {
130 	fprintf( stderr, "Bad focus attempt\n" );
131 return;
132     }
133 
134     // We recurse and find the top-level gadget.
135     for ( top=g->base; top->parent!=NULL && !top->is_toplevel ; top=top->parent );
136     td = (GTopLevelD *) (top->widget_data);
137 
138     // We check whether the gadget in question has focus.
139     if ( td->gfocus!=g ) {
140       // If not, we try to deal with the lack of focus.
141 /* Hmm. KDE doesn't give us a focus out event when we make a window invisible */
142 /*  So to be on the save side lets send local focus out events even when not */
143 /*  strictly needed */
144 	if ( /*top == current_focus_window &&*/ td->gfocus!=NULL &&
145 		td->gfocus->funcs->handle_focus!=NULL ) {
146             // We use the focus handler provided by the presently focussed gadget and process a loss-of-focus event for the currently focused object.
147             memset(&e, 0, sizeof(GEvent));
148 	    e.type = et_focus;
149 	    e.w = top;
150 	    e.u.focus.gained_focus = false;
151 	    e.u.focus.mnemonic_focus = mf_normal;
152 	    (td->gfocus->funcs->handle_focus)(td->gfocus,&e);
153 	}
154     }
155     // We give focus to the desired gadget.
156     td->gfocus = g;
157     if ( top == current_focus_window && g->funcs->handle_focus!=NULL ) {
158         // If the desired gadget has a focus handler, we construct an event and run it.
159         memset(&e, 0, sizeof(GEvent));
160 	e.u.focus.gained_focus = true;
161 	e.u.focus.mnemonic_focus = mf;
162 	(g->funcs->handle_focus)(g,&e);
163     }
164 }
165 
GWidgetIndicateFocusGadget(GGadget * g)166 void GWidgetIndicateFocusGadget(GGadget *g) {
167     _GWidget_IndicateFocusGadget(g,mf_normal);
168 }
169 
_GWidget_FindPost(GContainerD * cd,GGadget * oldfocus,GGadget ** last)170 static GGadget *_GWidget_FindPost(GContainerD *cd,GGadget *oldfocus,GGadget **last) {
171     GGadget *g;
172     GWidgetD *w;
173 
174     if ( cd==NULL || !cd->iscontainer )
175 return( false );
176     for ( g=cd->gadgets; g!=NULL; g=g->prev ) {
177 	if ( g==oldfocus )
178 return( *last );
179 	if ( g->focusable && g->state!=gs_invisible && g->state!=gs_disabled )
180 	    *last = g;
181     }
182     for ( w=cd->widgets; w!=NULL; w=w->next ) {
183 	if (( g = _GWidget_FindPost((GContainerD *) w,oldfocus,last))!=NULL )
184 return( g );
185     }
186 return( NULL );
187 }
188 
GWidgetNextFocus(GWindow top)189 void GWidgetNextFocus(GWindow top) {
190     GTopLevelD *topd;
191     GGadget *focus, *last=NULL;
192 
193     while ( top->parent!=NULL && !top->is_toplevel ) top = top->parent;
194     topd = (GTopLevelD *) (top->widget_data);
195     if ( topd==NULL || topd->gfocus == NULL )
196 return;
197     if ( (focus = _GWidget_FindPost((GContainerD *) topd,topd->gfocus,&last))== NULL ) {
198 	/* if we didn't find a Next Gadget, it's either because: */
199 	/*  1) the focus gadget is first in the chain, in which case we want */
200 	/*	the last thing in the chain */
201 	/*  2) our data structures are screwed up */
202 	_GWidget_FindPost((GContainerD *) topd,NULL,&last);
203 	focus = last;
204     }
205     _GWidget_IndicateFocusGadget(focus,mf_tab);
206 }
207 
_GWidget_FindPrev(GContainerD * cd,GGadget * oldfocus,GGadget ** first,int * found)208 static GGadget *_GWidget_FindPrev(GContainerD *cd,GGadget *oldfocus,GGadget **first, int *found) {
209     GGadget *g;
210     GWidgetD *w;
211 
212     if ( cd==NULL || !cd->iscontainer )
213 return( false );
214     for ( g=cd->gadgets; g!=NULL; g=g->prev ) {
215 	if ( g->focusable && g->state!=gs_invisible && g->state!=gs_disabled ) {
216 	    if ( *first==NULL )
217 		*first = g;
218 	    if ( *found )
219 return( g );
220 	}
221 	if ( g==oldfocus )
222 	    *found = true;
223     }
224     for ( w=cd->widgets; w!=NULL; w=w->next ) {
225 	if (( g = _GWidget_FindPrev((GContainerD *) w,oldfocus,first,found))!=NULL )
226 return( g );
227     }
228 return( NULL );
229 }
230 
GWidgetPrevFocus(GWindow top)231 void GWidgetPrevFocus(GWindow top) {
232     GTopLevelD *topd;
233     GGadget *focus;
234 
235     while ( top->parent!=NULL && !top->is_toplevel ) top = top->parent;
236     topd = (GTopLevelD *) (top->widget_data);
237     if ( topd==NULL || topd->gfocus == NULL )
238 return;
239     for ( focus = topd->gfocus->prev;
240 	    focus!=NULL && (!focus->focusable || focus->state==gs_invisible || focus->state==gs_disabled);
241 	    focus = focus->prev );
242     if ( focus==NULL ) {
243 	GGadget *first = NULL; int found = false;
244 	if ( (focus = _GWidget_FindPrev((GContainerD *) topd,topd->gfocus,&first,&found))== NULL )
245 	    focus = first;
246     }
247     _GWidget_IndicateFocusGadget(focus,mf_tab);
248 }
249 
_GWidget_Container_eh(GWindow gw,GEvent * event)250 static int _GWidget_Container_eh(GWindow gw, GEvent *event) {
251 /* Gadgets can get mouse, char and expose events */
252 /* Widgets might need char events redirected to them */
253 /* If a gadget doesn't want an event it returns false from its eh */
254 /* If a subwidget doesn't want an event it may send it up to us */
255     int handled = false;
256     GGadget *gadget;
257     GContainerD *gd = (GContainerD *) (gw->widget_data);
258     GWindow pixmap;
259     GWindow parent;
260     GTopLevelD *topd;
261 
262     if ( gd==NULL )			/* dying */
263 return(true);
264 
265     for ( parent = gw; parent->parent!=NULL && parent->parent->widget_data!=NULL &&
266 	    !parent->is_toplevel; parent = parent->parent );
267     topd = (GTopLevelD *) (parent->widget_data);
268     if ( topd==NULL )
269 	fprintf( stderr, "No top level window found\n" );
270 
271     GGadgetPopupExternalEvent(event);
272     if ( event->type == et_expose ) {
273 	GRect old;
274 
275 	pixmap = _GWidget_GetPixmap(gw,&event->u.expose.rect);
276 	pixmap->ggc->bg = gw->ggc->bg;
277 	GDrawPushClip(pixmap,&event->u.expose.rect,&old);
278 	pixmap->user_data = gw->user_data;
279 
280 	if ( gd->e_h!=NULL ) {
281 	    (gd->e_h)(pixmap,event);
282 	}
283 	for ( gadget = gd->gadgets; gadget!=NULL ; gadget=gadget->prev )
284 	    if ( ! ( gadget->r.x>event->u.expose.rect.x+event->u.expose.rect.width ||
285 		    gadget->r.y>event->u.expose.rect.y+event->u.expose.rect.height ||
286 		    gadget->r.x+gadget->r.width<event->u.expose.rect.x ||
287 		    gadget->r.y+gadget->r.height<event->u.expose.rect.y ) &&
288 		    gadget->state!=gs_invisible )
289 		(gadget->funcs->handle_expose)(pixmap,gadget,event);
290 
291 	GDrawPopClip(pixmap,&old);
292 	_GWidget_RestorePixmap(gw,pixmap,&event->u.expose.rect);
293 
294 return( true );
295     } else if ( event->type >= et_mousemove && event->type <= et_crossing ) {
296 	if ( topd!=NULL && topd->popupowner!=NULL ) {
297 	    handled = (topd->popupowner->funcs->handle_mouse)(topd->popupowner,event);
298 return( handled );
299 	}
300 	if ( gd->grabgadget && event->type==et_mousedown &&
301 		(event->u.mouse.state&ksm_buttons)==0 )
302 	    gd->grabgadget = NULL;		/* Happens if a gadget invokes a popup menu. Gadget remains grabbed because menu gets the mouse up */
303 	if ( gd->grabgadget!=NULL ) {
304 	    handled = (gd->grabgadget->funcs->handle_mouse)(gd->grabgadget,event);
305 	    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
306 		    gw->is_dying || gw->widget_data==NULL )
307 return( true );
308 	    if ( event->type==et_mouseup )
309 		gd->grabgadget = NULL;
310 	} else if ( event->type==et_mousedown ) {
311 	    if ( !parent->is_popup )
312 		last_input_window = parent;
313 	    for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
314 		if ( gadget->state!=gs_disabled && gadget->state!=gs_invisible &&
315 			gadget->takes_input &&
316 			GGadgetWithin(gadget,event->u.mouse.x,event->u.mouse.y)) {
317 		    handled = (gadget->funcs->handle_mouse)(gadget,event);
318 		    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
319 			    gw->is_dying || gw->widget_data==NULL )
320 return( true );
321 		    gd->grabgadget = gadget;
322 		    if ( gadget->focusable && handled )
323 			GWidgetIndicateFocusGadget(gadget);
324 		}
325 	    }
326 	} else {
327 	    for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
328 		if ( !gadget->state!=gs_disabled && gadget->state!=gs_invisible &&
329 			/*gadget->takes_input &&*/	/* everybody needs mouse moves for popups, even labels */
330 			GGadgetWithin(gadget,event->u.mouse.x,event->u.mouse.y)) {
331 		    if ( gd->lastwiggle!=NULL && gd->lastwiggle!=gadget )
332 			(gd->lastwiggle->funcs->handle_mouse)(gd->lastwiggle,event);
333 		    handled = (gadget->funcs->handle_mouse)(gadget,event);
334 		    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
335 			    gw->is_dying || gw->widget_data==NULL )
336 return( true );
337 		    gd->lastwiggle = gadget;
338 		}
339 	    }
340 	    if ( !handled && gd->lastwiggle!=NULL ) {
341 		(gd->lastwiggle->funcs->handle_mouse)(gd->lastwiggle,event);
342 		if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
343 			gw->is_dying )
344 return( true );
345 	    }
346 	}
347     } else if ( event->type == et_char || event->type == et_charup ) {
348 	if ( topd!=NULL ) {
349 	    handled = (topd->handle_key)(parent,gw,event);
350 	}
351     } else if ( event->type == et_drag || event->type == et_dragout || event->type==et_drop ) {
352 	GGadget *lastdd = NULL;
353 	GEvent e;
354 	for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
355 	    if ( gadget->funcs->handle_sel &&
356 		    GGadgetWithin(gadget,event->u.drag_drop.x,event->u.drag_drop.y))
357 		if (( handled = (gadget->funcs->handle_sel)(gadget,event) )) {
358 		    lastdd = gadget;
359 		    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
360 			    gw->is_dying )
361 return( true );
362 		    }
363 	}
364 	if ( !handled && gd->e_h!=NULL ) {
365 	    handled = (gd->e_h)(gw,event);
366 	    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
367 		    gw->is_dying )
368 return( true );
369 	    lastdd = (GGadget *) -1;
370 	}
371 	e.type = et_dragout;
372 	e.w = gw;
373 	if ( lastdd!=gd->lastddgadget ) {
374 	    if ( gd->lastddgadget==(GGadget *) -1 )
375 		(gd->e_h)(gw,&e);
376 	    else if ( gd->lastddgadget!=NULL )
377 		(gd->lastddgadget->funcs->handle_sel)(gd->lastddgadget,&e);
378 	    if ( !GDrawNativeWindowExists(NULL,event->native_window) ||
379 		    gw->is_dying )
380 return( true );
381 	}
382 	if ( event->type==et_drag )
383 	    gd->lastddgadget = lastdd;
384 	else
385 	    gd->lastddgadget = NULL;
386 return( handled );
387     } else if ( event->type == et_selclear ) {
388 	for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
389 	    if ( gadget->funcs->handle_sel ) {
390 		if ( (handled = (gadget->funcs->handle_sel)(gadget,event)) )
391 	break;
392 	    }
393 	}
394     } else if ( event->type == et_timer ) {
395 	for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
396 	    if ( gadget->funcs->handle_timer ) {
397 		if ( (handled = (gadget->funcs->handle_timer)(gadget,event)) )
398 	break;
399 	    }
400 	}
401     } else if ( event->type == et_resize ) {
402 	GWidgetFlowGadgets(gw);
403     }
404     if ( gd->e_h!=NULL && (!handled || event->type==et_mousemove ))
405 	handled = (gd->e_h)(gw,event);
406     if ( event->type == et_destroy ) {
407 	GGadget *prev;
408 	for ( gadget = gd->gadgets; gadget!=NULL ; gadget=prev ) {
409 	    prev = gadget->prev;
410 	    if ( !gadget->contained )
411 		(gadget->funcs->destroy)(gadget);
412 	    /* contained ggadgets will be destroyed when their owner is destroyed */
413 	}
414 	/* Widgets are windows and should get their own destroy events and free themselves */
415 	/* remove us from our parent */
416 	parent = gw->parent;
417 	if ( parent!=NULL && parent->widget_data!=NULL ) {
418 	    GContainerD *pgd = (GContainerD *) (parent->widget_data);
419 	    struct gwidgetdata *wd, *pwd;
420 	    for ( pwd=NULL, wd=pgd->widgets; wd!=NULL && wd!=(struct gwidgetdata *) gd; pwd = wd, wd = wd->next );
421 	    if ( pwd==NULL )
422 		pgd->widgets = gd->next;
423 	    else
424 		pwd->next = gd->next;
425 	}
426 	free(gd);
427 	gw->widget_data = NULL;
428     }
429 return( handled );
430 }
431 
GWidgetCheckMn(GContainerD * gd,GEvent * event)432 static int GWidgetCheckMn(GContainerD *gd,GEvent *event) {
433     int handled = false;
434     GGadget *gadget, *last;
435     struct gwidgetdata *widget;
436     unichar_t keysym = event->u.chr.keysym;
437     int mask = GMenuMask() & (ksm_control|ksm_cmdmacosx);
438 
439     if ( (mask&ksm_cmdmacosx) && keysym>0x7f &&
440 	    (event->u.chr.state&ksm_meta) && !(event->u.chr.state&mask) )
441 	keysym = GGadgetUndoMacEnglishOptionCombinations(event);
442 
443     if ( islower(keysym)) keysym = toupper(keysym);
444     for ( gadget = gd->gadgets; gadget!=NULL && !handled ; gadget=gadget->prev ) {
445 	if ( (event->u.chr.state&ksm_meta) && !(event->u.chr.state&mask) &&
446 		gadget->mnemonic==keysym &&
447 		gadget->state != gs_invisible && gadget->state != gs_disabled ) {
448 	    if ( gadget->focusable ) {	/* labels may have a mnemonic */
449 		    /* (ie. because textfields can't display mnemonics) */
450 		    /* but they don't act on it */
451 		_GWidget_IndicateFocusGadget(gadget,mf_mnemonic);
452 		handled = true;
453 	    } else if ( last!=NULL && last->mnemonic=='\0' ) {
454 		/* So if we get a label with a mnemonic, and the next gadget */
455 		/*  is focusable and doesn't have a mnemoic itself, give it */
456 		/*  the label's focus */
457 		_GWidget_IndicateFocusGadget(last,mf_mnemonic);
458 		handled = true;
459 	    }
460 	} else if ( gadget->shortcut == keysym &&
461 		(gadget->short_mask&event->u.chr.state)==gadget->short_mask ) {
462 	    _GWidget_IndicateFocusGadget(gadget,mf_shortcut);
463 	    handled = true;
464 	} else if ( gadget->state != gs_invisible &&
465 		gadget->state != gs_disabled &&
466 		gadget->focusable ) {
467 	    last = gadget;
468 	}
469     }
470     for ( widget = gd->widgets; widget!=NULL && !handled ; widget=widget->next ) {
471 	if ( widget->iscontainer )
472 	    handled = GWidgetCheckMn((GContainerD *) widget,event);
473     }
474 return( handled );
475 }
476 
_GWidget_TopLevel_Key(GWindow top,GWindow ew,GEvent * event)477 static int _GWidget_TopLevel_Key(GWindow top, GWindow ew, GEvent *event) {
478     GTopLevelD *topd = (GTopLevelD *) (top->widget_data);
479     int handled=0;
480     GEvent sub;
481 
482     if ( !top->is_popup )
483 	last_input_window = top;
484 
485     /* If the palette has the focus, and it usually will under kde, then */
486     /*  give the event to the main window if the cursor is outside of the palette */
487     if ( topd->ispalette ) {
488 	if ( event->u.chr.x<-2 || event->u.chr.x>top->pos.width+2 ||
489 		event->u.chr.y<-2 || event->u.chr.y>top->pos.height+2 ) {
490 	    GPoint p;
491 	    topd = topd->owner;
492 	    p.x = event->u.chr.x; p.y = event->u.chr.y;
493 	    GDrawTranslateCoordinates(ew,topd->w,&p);
494 	    event->u.chr.x = p.x; event->u.chr.y = p.y;
495 	    ew = top = topd->w;
496 	    event->w = top;
497 	}
498     }
499     /* Check for mnemonics and shortcuts */
500     if ( event->type == et_char && !GKeysymIsModifier(event->u.chr.keysym) ) {
501 	handled = GMenuPopupCheckKey(event);
502 	if ( topd->ispalette ) {
503 	    if ( !(handled = GMenuBarCheckKey(top,topd->owner->gmenubar,event)) )
504 		handled = GWidgetCheckMn((GContainerD *) topd->owner,event);
505 	}
506 	if ( !handled )
507 	    if ( !(handled = GMenuBarCheckKey(top,topd->gmenubar,event)) )
508 		handled = GWidgetCheckMn((GContainerD *) topd,event);
509     }
510     if ( handled )
511 	/* No op */;
512     else if ( topd->popupowner!=NULL ) {
513 	/* When we've got an active popup (menu, list, etc.) all key events */
514 	/*  go to the popups owner (which, presumably sends them to the popup)*/
515 	if ( topd->popupowner->funcs->handle_key !=NULL )
516 	    handled = (topd->popupowner->funcs->handle_key)(topd->popupowner,event);
517     } else if ( topd->gfocus!=NULL && topd->gfocus->funcs->handle_key )
518 	handled = (topd->gfocus->funcs->handle_key)(topd->gfocus,event);
519     if ( !handled ) {
520 	if ( ew->widget_data==NULL ) {
521 	    if ( ew->eh!=NULL )
522 		handled = (ew->eh)(ew,event);
523 	} else if ( ew->widget_data->e_h!=NULL )
524 	    handled = (ew->widget_data->e_h)(ew,event);
525     }
526 
527     if ( event->type==et_charup )
528 return( handled );
529     /* If no one wanted it then try keyboard navigation */
530     /* Tab or back tab cycles the focus through our widgets/gadgets */
531     if ( !handled && (event->u.chr.keysym==GK_Tab || event->u.chr.keysym==GK_BackTab )) {
532 	if ( event->u.chr.keysym==GK_BackTab || (event->u.chr.state&ksm_shift) )
533 	    GWidgetPrevFocus(ew);
534 	else
535 	    GWidgetNextFocus(ew);
536 	handled = true;
537     }
538     /* Return activates the default button (if there is one) */
539     else if ( !handled && (event->u.chr.keysym==GK_Return || event->u.chr.keysym==GK_KP_Enter) &&
540 	    topd->gdef!=NULL ) {
541 	sub.type = et_controlevent;
542 	sub.w = topd->gdef->base;
543 	sub.u.control.subtype = et_buttonactivate;
544 	sub.u.control.g = topd->gdef;
545 	sub.u.control.u.button.clicks = 0;
546 	if ( topd->gdef->handle_controlevent != NULL )
547 	    (topd->gdef->handle_controlevent)(topd->gdef,&sub);
548 	else
549 	    GDrawPostEvent(&sub);
550     }
551     /* Escape activates the cancel button (if there is one) */
552     /*  (On the mac, Command-. has that meaning) */
553     else if ( !handled && topd->gcancel!=NULL &&
554 	    (event->u.chr.keysym==GK_Escape ||
555 	     ((GMenuMask()&ksm_cmdmacosx) &&
556 	      (event->u.chr.state&GMenuMask())==ksm_cmdmacosx &&
557 	      event->u.chr.keysym=='.'))) {
558 	sub.type = et_controlevent;
559 	sub.w = topd->gcancel->base;
560 	sub.u.control.subtype = et_buttonactivate;
561 	sub.u.control.g = topd->gcancel;
562 	sub.u.control.u.button.clicks = 0;
563 	if ( topd->gcancel->handle_controlevent != NULL )
564 	    (topd->gcancel->handle_controlevent)(topd->gcancel,&sub);
565 	else
566 	    GDrawPostEvent(&sub);
567     }
568 return( handled );
569 }
570 
GiveToAll(GContainerD * wd,GEvent * event)571 static int GiveToAll(GContainerD *wd, GEvent *event) {
572     GGadget *g;
573     GContainerD *sub;
574 
575     if ( wd!=NULL && wd->iscontainer ) {
576 	for ( g=wd->gadgets; g!=NULL; g=g->prev )
577 	    if ( g->funcs->handle_mouse!=NULL )
578 		(g->funcs->handle_mouse)(g,event);
579 	for ( sub = (GContainerD *) (wd->widgets); sub!=NULL;
580 		sub=(GContainerD *) (sub->next) )
581 	    GiveToAll(sub,event);
582     }
583     if ( wd!=NULL ) {
584 	if ( wd->e_h!=NULL )
585 	    (wd->e_h)(wd->w,event);
586     } else {
587 	if ( wd->w->eh!=NULL )
588 	    (wd->w->eh)(wd->w,event);
589     }
590 return( true );
591 }
592 
ManagePalettesVis(GTopLevelD * td,int is_visible)593 static void ManagePalettesVis(GTopLevelD *td, int is_visible ) {
594     GTopLevelD *palette;
595 
596     if ( td->w!=last_paletted_focus_window )
597 return;
598     for ( palette=td->palettes; palette!=NULL; palette = palette->nextp ) {
599 	if ( is_visible && palette->w->visible_request )
600 	    GDrawSetVisible(palette->w,true);
601 	else if ( !is_visible && palette->w->visible_request ) {
602 	    GDrawSetVisible(palette->w,false);
603 	    palette->w->visible_request = true;
604 	}
605     }
606 }
607 
608 static GTopLevelD *oldtd = NULL;
609 static GGadget *oldgfocus = NULL;
610 
_GWidget_TopLevel_eh(GWindow gw,GEvent * event)611 static int _GWidget_TopLevel_eh(GWindow gw, GEvent *event) {
612     GTopLevelD *td;
613     int ret;
614 
615     if ( !GDrawNativeWindowExists(NULL,event->native_window) )
616 return( true );
617 
618     td = (GTopLevelD *) (gw->widget_data);
619     if ( td==NULL )		/* Dying */
620 return( true );
621 
622     GGadgetPopupExternalEvent(event);
623     if ( event->type==et_focus ) {
624 
625 	if ( event->u.focus.gained_focus ) {
626 	    if ( gw->is_toplevel && !gw->is_popup && !gw->is_dying ) {
627 		if ( last_input_window!=gw )
628 		    previous_focus_window = last_input_window;
629 		current_focus_window = gw;
630 	    }
631 	} else if ( current_focus_window==gw ) {
632 	    current_focus_window = NULL;
633 	}
634 	if ( !td->ispalette && gw->is_visible && event->u.focus.gained_focus && !gw->is_dying ) {
635 	    GWindow dlg = GDrawGetRedirectWindow(NULL);
636 	    if ( dlg==NULL || dlg==gw ) {
637 		/* If top level window loses the focus all its palettes go invisible */
638 		/* if it gains focus then all palettes that are supposed to be vis */
639 		/*  become visible */
640 		/* But not if we've got an active dialog */
641 		GTopLevelD *palette;
642 		if ( last_paletted_focus_window!=NULL && !last_paletted_focus_window->is_dying ) {
643 		    GTopLevelD *lpfw_td = (GTopLevelD *) (last_paletted_focus_window->widget_data);
644 		    for ( palette=lpfw_td->palettes; palette!=NULL; palette = palette->nextp ) {
645 			if ( !palette->w->is_visible && palette->w->visible_request ) {
646 			    GDrawSetVisible(palette->w,false);
647 			    palette->w->visible_request = true;
648 			}
649 		    }
650 		}
651 		for ( palette=td->palettes; palette!=NULL; palette = palette->nextp ) {
652 		    if ( !palette->w->is_visible && palette->w->visible_request )
653 			GDrawSetVisible(palette->w,true);
654 		}
655 		last_paletted_focus_window = gw;
656 	    }
657 	}
658 	if ( !gw->is_dying && td->gfocus!=NULL && td->gfocus->funcs->handle_focus!=NULL ) {
659  { oldtd = td; oldgfocus = td->gfocus; }	/* Debug!!!! */
660 	    (td->gfocus->funcs->handle_focus)(td->gfocus,event);
661 	}
662 	if ( !gw->is_dying && td->e_h!=NULL )
663 	    (td->e_h)(gw,event);
664 return( true );
665     } else if ( !gw->is_dying && event->type == et_crossing ) {
666 	GiveToAll((GContainerD *) td,event);
667 return( true );
668     } else if ( event->type == et_char || event->type == et_charup ) {
669         // If this is not a nested event, redirect it at the window that
670         // contains the currently focused gadget.
671         if (!td->isnestedkey && td->gfocus && td->gfocus->base) {
672             td->isnestedkey = true;
673             ret = _GWidget_TopLevel_Key(gw, td->gfocus->base, event);
674             td->isnestedkey = false;
675         } else {
676             ret = _GWidget_TopLevel_Key(gw, gw, event);
677         }
678         return ret;
679     } else if ( !gw->is_dying && event->type == et_resize ) {
680 	GRect r;
681 	if ( td->gmenubar!=NULL ) {
682 	    GGadgetGetSize(td->gmenubar,&r);
683 	    GGadgetResize(td->gmenubar,event->u.resize.size.width,r.height);
684 	    GGadgetRedraw(td->gmenubar);
685 	} /* status line, toolbar, etc. */
686 	if ( td->palettes!=NULL && event->u.resize.moved ) {
687 	    GTopLevelD *palette;
688 	    for ( palette=td->palettes; palette!=NULL; palette = palette->nextp ) {
689 		if ( !broken_palettes || !palette->positioned_yet ) {
690 		    int x = gw->pos.x + palette->owner_off_x,
691 			y = gw->pos.y + palette->owner_off_y;
692 		    if ( x<0 ) x=0;
693 		    if ( y<0 ) y=0;
694 		    if ( x+palette->w->pos.width>GDrawGetRoot(NULL)->pos.width )
695 			x = GDrawGetRoot(NULL)->pos.width-palette->w->pos.width;
696 		    if ( y+palette->w->pos.height>GDrawGetRoot(NULL)->pos.height )
697 			y = GDrawGetRoot(NULL)->pos.height-palette->w->pos.height;
698 		    ++palette->programmove;
699 		    if ( gw->is_visible )
700 			GDrawTrueMove(palette->w, x, y);
701 		    else
702 			GDrawMove(palette->w, x, y);
703 		    palette->positioned_yet = true;
704 		}
705 	    }
706 	}
707 	if ( td->ispalette ) {
708 	    if ( td->programmove>0 )
709 		--td->programmove;
710 	    else {
711 		td->owner_off_x = gw->pos.x - td->owner->w->pos.x;
712 		td->owner_off_y = gw->pos.y - td->owner->w->pos.y;
713 	    }
714 	}
715     } else if ( event->type == et_close && td->ispalette ) {
716 	GDrawSetVisible(gw,false);
717 return( true );
718     } else if ( !gw->is_dying && event->type == et_visibility ) {
719 	if ( broken_palettes )
720 	    /* Do Nothing */;
721 	else if ( td->ispalette && event->u.visibility.state!=vs_unobscured ) {
722 	    if ( !GDrawIsAbove(gw,td->owner->w))
723 		GDrawRaiseAbove(gw,td->owner->w);
724 	}
725     } else if ( !gw->is_dying && event->type == et_map && !td->ispalette ) {
726 	/* If top level window goes invisible all its palettes follow */
727 	/* if it goes visible then all palettes that are supposed to be vis */
728 	/*  follow */
729 	ManagePalettesVis(td, event->u.map.is_visible );
730     }
731     if ( event->type == et_destroy ) {
732 	if ( td->palettes!=NULL ) {
733 	    struct gtopleveldata *palettes, *next;
734 	    for ( palettes=td->palettes; palettes!=NULL; palettes = next ) {
735 		next = palettes->nextp;
736 		GDrawDestroyWindow(palettes->w);
737 	    }
738 	    /* Palettes must die before our widget data are freed */
739 	    GDrawSync(GDrawGetDisplayOfWindow(gw));
740 	    GDrawProcessPendingEvents(GDrawGetDisplayOfWindow(gw));
741 	}
742     }
743     ret = _GWidget_Container_eh(gw,event);
744     if ( event->type == et_destroy ) {
745 	if ( gw==current_focus_window )
746 	    current_focus_window = NULL;
747 	if ( gw==previous_focus_window )
748 	    previous_focus_window = NULL;
749 	if ( gw==last_input_window )
750 	    last_input_window = NULL;
751 	if ( gw==last_paletted_focus_window )
752 	    last_paletted_focus_window = NULL;
753 	ret = true;
754     }
755 return( ret );
756 }
757 
758 static struct wfuncs _gwidget_container_funcs;
759 static struct wfuncs _gwidget_toplevel_funcs;
760 
MakeContainerWidget(GWindow gw)761 static void MakeContainerWidget(GWindow gw) {
762     struct gwidgetcontainerdata *gd;
763 
764     if ( gw->widget_data!=NULL )
765 	GDrawIError( "Attempt to make a window into a widget twice");
766     if ( !widgets_initted )
767 	gwidget_init();
768     if ( gw->parent==NULL || gw->is_toplevel )
769 	gd = calloc(1,sizeof(struct gtopleveldata));
770     else
771 	gd = calloc(1,sizeof(struct gwidgetcontainerdata));
772     gw->widget_data = (struct gwidgetdata *) gd;
773     gd->w = gw;
774     gd->e_h = gw->eh;
775     gw->eh = _GWidget_Container_eh;
776     gd->enabled = true;
777     gd->iscontainer = true;
778     gd->funcs = &_gwidget_container_funcs;
779     if ( gw->parent!=NULL && !gw->is_toplevel ) {
780 	if ( gw->parent->widget_data==NULL )
781 	    MakeContainerWidget(gw->parent);
782 	if ( !gw->parent->widget_data->iscontainer )
783 	    GDrawIError( "Attempt to add a widget to something which is not a container");
784 	gd->next = ((struct gwidgetcontainerdata *) (gw->parent->widget_data))->widgets;
785 	((struct gwidgetcontainerdata *) (gw->parent->widget_data))->widgets =
786 		(struct gwidgetdata *) gd;
787     } else {
788 	struct gtopleveldata *topd;
789 	topd = (struct gtopleveldata *) gd;
790 	gd->funcs = &_gwidget_toplevel_funcs;
791 	gw->eh = _GWidget_TopLevel_eh;
792 	topd->handle_key = _GWidget_TopLevel_Key;
793 	topd->istoplevel = true;
794     }
795 }
796 
_GWidget_AddGGadget(GWindow gw,GGadget * g)797 void _GWidget_AddGGadget(GWindow gw,GGadget *g) {
798     struct gwidgetcontainerdata *gd;
799 
800     if ( gw->widget_data==NULL )
801 	MakeContainerWidget(gw);
802     gd = (struct gwidgetcontainerdata *) (gw->widget_data);
803     if ( !gd->iscontainer )
804 	GDrawIError( "Attempt to add a gadget to something which is not a container");
805     g->prev = gd->gadgets;
806     gd->gadgets = g;
807     if ( g->base!=NULL )
808 	GDrawIError( "Attempt to add a gadget to two widgets" );
809     g->base = gw;
810 }
811 
_GWidget_RemoveGadget(GGadget * g)812 void _GWidget_RemoveGadget(GGadget *g) {
813     struct gwidgetcontainerdata *gd;
814     GTopLevelD *td;
815     GWindow gw = g->base;
816     GGadget *next;
817 
818     if ( gw==NULL )
819 return;
820 
821     gd = (struct gwidgetcontainerdata *) (gw->widget_data);
822     if ( gd==NULL || !gd->iscontainer )
823 	GDrawIError( "Attempt to remove a gadget to something which is not a container");
824     if ( gd->gadgets==g )
825 	gd->gadgets = g->prev;
826     else {
827 	for ( next = gd->gadgets; next!=NULL && next->prev!=g; next = next->prev );
828 	if ( next==NULL )
829 	    GDrawIError( "Attempt to remove a gadget which is not in the gadget list" );
830 	else
831 	    next->prev = g->prev;
832     }
833     if ( gd->grabgadget == g ) gd->grabgadget = NULL;
834     g->prev = NULL;
835     g->base = NULL;
836 
837     while ( gw->parent!=NULL && !gw->is_toplevel ) gw = gw->parent;
838     td = (GTopLevelD *) (gw->widget_data);
839     if ( td->gdef == g ) td->gdef = NULL;
840     if ( td->gcancel == g ) td->gcancel = NULL;
841     if ( td->gfocus == g ) td->gfocus = NULL;
842 }
843 
_GWidget_SetDefaultButton(GGadget * g)844 void _GWidget_SetDefaultButton(GGadget *g) {
845     struct gtopleveldata *gd=NULL;
846     GWindow gw = g->base;
847 
848     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
849     if ( gw!=NULL )
850 	gd = (struct gtopleveldata *) (gw->widget_data);
851     if ( gd==NULL || !gd->istoplevel )
852 	GDrawIError( "This gadget isn't in a top level widget, can't be a default button" );
853     else
854 	gd->gdef = g;
855 }
856 
857 /* The previous function assumes everything is set up properly. This one doesn't */
858 /*  it's for when you've got two buttons which might be default and you toggle */
859 /*  between them. It lets each button know if it's default, and then redraws */
860 /*  both */
_GWidget_MakeDefaultButton(GGadget * g)861 void _GWidget_MakeDefaultButton(GGadget *g) {
862     struct gtopleveldata *gd=NULL;
863     GWindow gw = g->base;
864 
865     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
866     if ( gw!=NULL )
867 	gd = (struct gtopleveldata *) (gw->widget_data);
868     if ( gd==NULL || !gd->istoplevel )
869 	GDrawIError( "This gadget isn't in a top level widget, can't be a default button" );
870     else if ( gd->gdef!=g ) {
871 	_GButton_SetDefault(gd->gdef,false);
872 	gd->gdef = g;
873 	_GButton_SetDefault(g,true);
874     }
875 }
876 
_GWidget_SetCancelButton(GGadget * g)877 void _GWidget_SetCancelButton(GGadget *g) {
878     struct gtopleveldata *gd=NULL;
879     GWindow gw = g->base;
880 
881     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
882     if ( gw!=NULL )
883 	gd = (struct gtopleveldata *) (gw->widget_data);
884     if ( gd==NULL || !gd->istoplevel )
885 	GDrawIError( "This gadget isn't in a top level widget, can't be a cancel button" );
886     else
887 	gd->gcancel = g;
888 }
889 
_GWidget_SetMenuBar(GGadget * g)890 void _GWidget_SetMenuBar(GGadget *g) {
891     struct gtopleveldata *gd=NULL;
892     GWindow gw = g->base;
893 
894     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
895     if ( gw!=NULL )
896 	gd = (struct gtopleveldata *) (gw->widget_data);
897     if ( gd==NULL || !gd->istoplevel )
898 	GDrawIError( "This gadget isn't in a top level widget, can't be a menubar" );
899     else
900 	gd->gmenubar = g;
901 }
902 
_GWidget_SetPopupOwner(GGadget * g)903 void _GWidget_SetPopupOwner(GGadget *g) {
904     struct gtopleveldata *gd=NULL;
905     GWindow gw = g->base;
906 
907     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
908     if ( gw!=NULL )
909 	gd = (struct gtopleveldata *) (gw->widget_data);
910     if ( gd==NULL || !gd->istoplevel )
911 	GDrawIError( "This gadget isn't in a top level widget, can't have a popup" );
912     else
913 	gd->popupowner = g;
914 }
915 
_GWidget_ClearPopupOwner(GGadget * g)916 void _GWidget_ClearPopupOwner(GGadget *g) {
917     struct gtopleveldata *gd=NULL;
918     GWindow gw = g->base;
919 
920     if ( gw!=NULL ) while ( gw->parent != NULL && !gw->is_toplevel ) gw = gw->parent;
921     if ( gw!=NULL )
922 	gd = (struct gtopleveldata *) (gw->widget_data);
923     if ( gd==NULL || !gd->istoplevel )
924 	GDrawIError( "This gadget isn't in a top level widget, can't have a popup" );
925     else
926 	gd->popupowner = NULL;
927 }
928 
_GWidget_SetGrabGadget(GGadget * g)929 void _GWidget_SetGrabGadget(GGadget *g) {
930     struct gwidgetcontainerdata *gd=NULL;
931     GWindow gw = g->base;
932 
933     if ( gw!=NULL )
934         gd = (struct gwidgetcontainerdata *) (gw->widget_data);
935     if ( gd==NULL || !gd->iscontainer )
936         GDrawIError( "This gadget isn't in a container, can't be a grab gadget" );
937     else
938         gd->grabgadget = g;
939 }
940 
_GWidget_ClearGrabGadget(GGadget * g)941 void _GWidget_ClearGrabGadget(GGadget *g) {
942     struct gwidgetcontainerdata *gd=NULL;
943     GWindow gw = g->base;
944 
945     if ( gw!=NULL )
946         gd = (struct gwidgetcontainerdata *) (gw->widget_data);
947     if ( gd==NULL || !gd->iscontainer )
948         GDrawIError( "This gadget isn't in a container, can't be a grab gadget" );
949     else
950         gd->grabgadget = NULL;
951 }
952 
GWidgetCreateTopWindow(GDisplay * gdisp,GRect * pos,int (* eh)(GWindow,GEvent *),void * user_data,GWindowAttrs * wattrs)953 GWindow GWidgetCreateTopWindow(GDisplay *gdisp, GRect *pos, int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
954     GWindow gw = GDrawCreateTopWindow(gdisp,pos,eh,user_data,wattrs);
955     MakeContainerWidget(gw);
956 return( gw );
957 }
958 
GWidgetCreateSubWindow(GWindow w,GRect * pos,int (* eh)(GWindow,GEvent *),void * user_data,GWindowAttrs * wattrs)959 GWindow GWidgetCreateSubWindow(GWindow w, GRect *pos, int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
960     GWindow gw = GDrawCreateSubWindow(w,pos,eh,user_data,wattrs);
961     MakeContainerWidget(gw);
962 return( gw );
963 }
964 
965 /* Palettes follow their owners when the owner moves around the screen */
966 /*  Palettes go invisible when the owner does, and become visible again when it does */
967 /*  Palettes are always on top of their owner */
968 /*  Palettes go invisible when the owner loses focus, and become visible when it gains focus */
GWidgetCreatePalette(GWindow w,GRect * pos,int (* eh)(GWindow,GEvent *),void * user_data,GWindowAttrs * wattrs)969 GWindow GWidgetCreatePalette(GWindow w, GRect *pos, int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
970     GWindow gw;
971     GPoint pt, base;
972     GRect newpos, ownerpos, screensize;
973     struct gtopleveldata *gd, *od;
974     GWindow root;
975 
976     if ( !w->is_toplevel )
977 return( false );
978 
979     pt.x = pos->x; pt.y = pos->y;
980     root = GDrawGetRoot(w->display);
981     GDrawGetSize(w,&ownerpos);
982     GDrawGetSize(root,&screensize);
983     GDrawTranslateCoordinates(w,root,&pt);
984     base.x = base.y = 0;
985     GDrawTranslateCoordinates(w,root,&base);
986     if ( pt.x<0 ) {
987 	if ( base.x+ownerpos.width+20+pos->width+20 > screensize.width )
988 	    pt.x=0;
989 	else
990 	    pt.x = base.x+ownerpos.width+20;
991     }
992     if ( pt.y<0 ) pt.y=0;
993     if ( pt.x+pos->width>root->pos.width )
994 	pt.x = root->pos.width-pos->width;
995     if ( pt.y+pos->height>root->pos.height )
996 	pt.y = root->pos.height-pos->height;
997 
998     newpos.x = pt.x; newpos.y = pt.y; newpos.width = pos->width; newpos.height = pos->height;
999     wattrs->event_masks |= (1<<et_visibility);
1000     if ( !(wattrs->mask&wam_transient)) {
1001 	wattrs->mask |= wam_transient;
1002 	wattrs->transient = GWidgetGetTopWidget(w);
1003     }
1004     if ( broken_palettes ) {
1005 	wattrs->mask |= wam_positioned;
1006 	wattrs->positioned = true;
1007     }
1008     gw = GDrawCreateTopWindow(w->display,&newpos,eh,user_data,wattrs);
1009     MakeContainerWidget(gw);
1010     if ( w->widget_data==NULL )
1011 	MakeContainerWidget(w);
1012     od = (struct gtopleveldata *) (w->widget_data);
1013     gd = (struct gtopleveldata *) (gw->widget_data);
1014     gd->nextp = od->palettes;
1015     gd->owner = od;
1016     od->palettes = gd;
1017     gd->ispalette = true;
1018     gd->owner_off_x = pos->x; gd->owner_off_y = pos->y;
1019 return( gw );
1020 }
1021 
GWidgetRequestVisiblePalette(GWindow palette,int visible)1022 void GWidgetRequestVisiblePalette(GWindow palette,int visible) {
1023     GTopLevelD *td = (GTopLevelD *) (palette->widget_data);
1024 
1025     if ( td->owner!=NULL ) {
1026 	palette->visible_request = visible;
1027 	if ( td->owner->w == last_paletted_focus_window )
1028 	    GDrawSetVisible(palette,visible);
1029     }
1030 }
1031 
GWidgetGetControl(GWindow gw,int cid)1032 GGadget *GWidgetGetControl(GWindow gw, int cid) {
1033     GGadget *gadget;
1034     GContainerD *gd = (GContainerD *) (gw->widget_data);
1035     GWidgetD *widg;
1036 
1037     if ( gd==NULL || !gd->iscontainer )
1038 return( NULL );
1039     for ( gadget = gd->gadgets; gadget!=NULL ; gadget=gadget->prev ) {
1040 	if ( gadget->cid == cid )
1041 return( gadget );
1042     }
1043     for ( widg = gd->widgets; widg!=NULL; widg = widg->next ) {
1044 	if ( widg->iscontainer ) {
1045 	    gadget = GWidgetGetControl(widg->w,cid);
1046 	    if ( gadget!=NULL )
1047 return( gadget );
1048 	}
1049     }
1050 return( NULL );
1051 }
1052 
_GWidgetGetGadgets(GWindow gw)1053 GGadget *_GWidgetGetGadgets(GWindow gw) {
1054     GContainerD *gd;
1055 
1056     if ( gw==NULL )
1057 return( NULL );
1058 
1059     gd = (GContainerD *) (gw->widget_data);
1060 
1061     if ( gd==NULL || !gd->iscontainer )
1062 return( NULL );
1063 
1064 return( gd->gadgets );
1065 }
1066 
GWidgetGetParent(GWindow gw)1067 GWindow GWidgetGetParent(GWindow gw) {
1068 
1069 return( gw->parent );
1070 }
1071 
GWidgetGetTopWidget(GWindow gw)1072 GWindow GWidgetGetTopWidget(GWindow gw) {
1073 
1074     for ( ; gw->parent!=NULL && !gw->is_toplevel; gw = gw->parent );
1075 return( gw );
1076 }
1077 
GWidgetGetEH(GWindow gw)1078 GDrawEH GWidgetGetEH(GWindow gw) {
1079     if ( gw->widget_data==NULL )
1080 return( gw->eh );
1081     else
1082 return( gw->widget_data->e_h );
1083 }
1084 
GWidgetSetEH(GWindow gw,GDrawEH e_h)1085 void GWidgetSetEH(GWindow gw, GDrawEH e_h ) {
1086     if ( gw->widget_data==NULL )
1087 	gw->eh = e_h;
1088     else
1089 	gw->widget_data->e_h = e_h;
1090 }
1091 
GWidgetHidePalettes(void)1092 void GWidgetHidePalettes(void) {
1093     GTopLevelD *td, *palette;
1094 
1095     if ( last_paletted_focus_window==NULL )
1096 return;
1097     td = (GTopLevelD *) (last_paletted_focus_window->widget_data);
1098     for ( palette=td->palettes; palette!=NULL; palette = palette->nextp ) {
1099 	if ( palette->w->visible_request ) {
1100 	    GDrawSetVisible(palette->w,false);
1101 	    palette->w->visible_request = true;
1102 	}
1103     }
1104 }
1105 
GWidgetCreateInputContext(GWindow w,enum gic_style def_style)1106 GIC *GWidgetCreateInputContext(GWindow w,enum gic_style def_style) {
1107     GWidgetD *wd = (GWidgetD *) (w->widget_data);
1108 
1109     if ( wd->gic==NULL )
1110 	wd->gic = GDrawCreateInputContext(w,def_style);
1111 return( wd->gic );
1112 }
1113 
GWidgetGetInputContext(GWindow w)1114 GIC *GWidgetGetInputContext(GWindow w) {
1115     GWidgetD *wd = (GWidgetD *) (w->widget_data);
1116 return( wd->gic );
1117 }
1118 
GWidgetFlowGadgets(GWindow gw)1119 void GWidgetFlowGadgets(GWindow gw) {
1120     GGadget *gadget;
1121     GContainerD *gd = (GContainerD *) (gw->widget_data);
1122 
1123     if ( gd==NULL )
1124 return;
1125 
1126     gadget = gd->gadgets;
1127     if ( gadget!=NULL ) {
1128 	while ( gadget->prev!=NULL )
1129 	    gadget=gadget->prev;
1130     }
1131     if ( gadget != NULL && GGadgetFillsWindow(gadget)) {
1132 	GRect wsize;
1133 	GDrawGetSize(gw, &wsize);
1134 
1135 	/* Make any offset simmetrical */
1136 	if (wsize.width >= 2*gadget->r.x) wsize.width -= 2*gadget->r.x;
1137 	else wsize.width = 0;
1138 
1139 	if (wsize.height >= 2*gadget->r.y) wsize.height -= 2*gadget->r.y;
1140 	else wsize.height = 0;
1141 
1142 	GGadgetResize(gadget,wsize.width,wsize.height);
1143 	GDrawRequestExpose(gw,NULL,false);
1144     }
1145 }
1146 
GWidgetToDesiredSize(GWindow gw)1147 void GWidgetToDesiredSize(GWindow gw) {
1148     GGadget *gadget;
1149     GContainerD *gd = (GContainerD *) (gw->widget_data);
1150 
1151     if ( gd==NULL )
1152 return;
1153 
1154     gadget = gd->gadgets;
1155     if ( gadget!=NULL ) {
1156 	while ( gadget->prev!=NULL )
1157 	    gadget=gadget->prev;
1158     }
1159     if ( gadget != NULL && GGadgetFillsWindow(gadget))
1160 	GHVBoxFitWindow(gadget);
1161 }
1162