2 * Purpose: central control of window sytem events.
6 /*----- Licensing note ----------------------------------------------------*
8 * This file is part of Straylight's Steel library.
10 * Steel is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * Steel is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Steel. If not, write to the Free Software Foundation,
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
47 /* -------- Keeping Track of All Windows. -------- */
49 typedef struct win__str {
50 struct win__str *next;
51 struct win__str *prev;
53 win_event_handler proc;
60 static win__str *win__allwindows;
62 static win__str *win__find(wimp_w w)
64 win__str *ws=win__allwindows;
74 static void win__register(wimp_w w, win_event_handler proc, void *handle)
77 win__str *ws=win__find(w);
81 if (ws=(win__str *)mem_alloc(sizeof(win__str)),ws==0)
86 msgs_lookup("winNEM:Not enough memory for new event handler.")
90 ws->next=win__allwindows;
93 win__allwindows->prev=ws;
103 static void win__discard(wimp_w w)
105 win__str *ws=win__find(w);
109 menu_attach(w,0,0,0,0); /* Try to free the menu */
111 ws->prev->next=ws->next;
113 win__allwindows=ws->next;
115 ws->next->prev=ws->prev;
120 BOOL win_read_eventhandler(wimp_w w,win_event_handler *p,void **handle)
122 win__str *ws=win__find(w);
131 /* -------- Claiming Events. -------- */
133 void win_register_event_handler(
134 wimp_w w, win_event_handler proc, void *handle)
139 win__register(w, proc, handle);
143 typedef struct unknown_previewer
145 struct unknown_previewer *link ;
146 win_unknown_event_processor proc ;
148 } unknown_previewer ;
150 typedef struct idle_receiver
152 struct idle_receiver *next;
153 win_idle_claimer proc;
159 static wimp_w win__idle = DUD;
160 #define win__unknown_flag (('U'<<24)+('N'<<16)+('K'<<8)+'N')
162 static wimp_w win__unknown = DUD;
163 static unknown_previewer *win__unknown_previewer_list;
164 static idle_receiver *idleList;
165 static int win__minPoll=2;
167 static void win__setPollingSpeed(void)
170 idle_receiver *p=idleList;
173 if (p->speed<s && p->speed!=win_DONTCARE)
177 wimpt_pollingTime(s);
180 void win_idleTime(int time)
183 win__setPollingSpeed();
186 void win_addIdleClaimer(win_idle_claimer proc,int speed,void *handle)
188 idle_receiver *new=(idle_receiver *)mem_alloc(sizeof(idle_receiver));
197 win__setPollingSpeed();
200 BOOL win_any_idles(void)
205 void win_remove_idle_claimer(win_idle_claimer proc,void *handle)
207 idle_receiver *block ;
208 for (block = (idle_receiver *) &idleList ;
209 block->next != 0 && (block->next->proc != proc || block->next->handle != handle) ;
210 block = block->next) ;
211 if (block->next != 0)
213 idle_receiver *b2 = block->next ;
214 block->next = b2->next ;
216 win__setPollingSpeed();
220 void win_claim_idle_events(wimp_w w)
222 tracef1("idle events -> %d\n",w) ;
226 wimp_w win_idle_event_claimer(void)
231 void win_claim_unknown_events(wimp_w w)
236 wimp_w win_unknown_event_claimer(void)
241 void win_add_unknown_event_processor(win_unknown_event_processor p,
244 unknown_previewer *block = mem_alloc(sizeof(unknown_previewer)) ;
247 block->link = win__unknown_previewer_list ;
250 win__unknown_previewer_list = block ;
254 void win_remove_unknown_event_processor(win_unknown_event_processor p,
257 unknown_previewer *block ;
258 for (block = (unknown_previewer *) &win__unknown_previewer_list ;
259 block != 0 && (block->link->proc != p || block->link->handle != h) ;
260 block = block->link) ;
263 unknown_previewer *b2 = block->link ;
264 block->link = b2->link ;
269 /* -------- Menus. -------- */
271 void win_setmenuh(wimp_w w, void *handle)
273 win__str *p = win__find(w);
274 if (p != 0) {p->menuh = handle;};
277 void *win_getmenuh(wimp_w w) /* 0 if not set */
279 win__str *p = win__find(w);
280 return(p==0 ? 0 : p->menuh);
283 /* -------- Processing Events. -------- */
286 * void win_broadcast(wimp_eventstr *e)
289 * Broadcasts the given event to ALL windows currently active. Note: this
290 * works in a similar way to module service calls - a broadcast can be
291 * 'claimed' by changing it to a null event. This is most useful for
292 * informing other windows about events (such as a parent window being
293 * closed), and thus message broadcasts should be used.
296 * wimp_eventstr *e == the event to broadcast.
299 void win_broadcast(wimp_eventstr *e)
301 win__str *p=win__allwindows;
307 (q->proc)(e,q->handle);
311 BOOL win_processevent(wimp_eventstr *e)
313 /* --- Houston, we have a problem --- *
315 * Event handlers can continue over several polls, unlike Sapphire where
316 * this sort of convolution is limited to coroutines. Our lists of
317 * handlers can become `stale' by the time the previous one finishes,
318 * if we're not careful. We bodge around the problem (bloody Acorn :-( )
319 * by keeping a static serial number, and a local copy. If the two don't
320 * match, we declare `stale!' and refuse to process any more events.
325 int cserial=++serial;
331 tracef1("win_processevent %i.\n", e->e);
335 idle_receiver *idles=idleList;
337 while (idles && cserial==serial) /* Avoid staleness of lists */
340 (idles->proc)(idles->handle);
347 w = win__unknown_flag ;
348 if (wimpt_getVersion()>=300)
349 os_swix(XDragASprite_Stop,&r);
352 wimpt_noerr(wimp_get_wind_state(e->data.o.w,&s));
353 if (wimpt_justChangedMode() || (s.flags & wimp_WCLICK_TOGGLE))
354 win_adjustBox(&e->data.o);
355 /* And continue... */
356 case wimp_EREDRAW: case wimp_ECLOSE:
357 case wimp_EPTRLEAVE: case wimp_EPTRENTER: case wimp_EKEY:
363 if (w <= (wimp_w) -1) w = win_ICONBAR;
364 if (wimpt_options() & wimpt_ONOWIMPSHADE)
367 wimpt_noerr(wimp_get_icon_info(e->data.but.m.w,e->data.but.m.i,&icn));
368 if ((icn.flags & 0x001f0000) == 0x001f0000)
373 case wimp_ESENDWANTACK:
374 switch (e->data.msg.hdr.action) {
375 case wimp_MCLOSEDOWN:
376 tracef0("closedown message\n");
380 tracef1("data %s message arriving.\n",
381 (int) (e->data.msg.hdr.action==wimp_MDATASAVE ? "save" : "load"));
382 if (e->data.msg.data.dataload.w < 0)
384 tracef0("data message to the icon bar.\n");
385 w = win_ICONBARLOAD ;
387 w = e->data.msg.data.dataload.w;
390 case wimp_MHELPREQUEST:
391 tracef1("help request for window %i.\n", e->data.msg.data.helprequest.m.w);
392 w = e->data.msg.data.helprequest.m.w;
393 if (w < 0) w = win_ICONBARLOAD;
396 tracef1("unknown message type %i arriving.\n", e->data.msg.hdr.action);
397 w = win__unknown_flag;
398 if (w < 0) w = win_ICONBARLOAD;
402 w = win__unknown_flag;
405 if (w==win__unknown_flag || win__find(w) == 0)
407 unknown_previewer *pr=win__unknown_previewer_list;
408 unknown_previewer *next;
409 while (pr != 0 && cserial==serial) /* Avoid staleness of lists */
412 if (pr->proc(e, pr->handle)) return TRUE ;
418 p = (w == DUD ? 0 : win__find(w));
420 p->proc(e, p->handle);
427 /* -------- Termination. -------- */
429 static int win__active;
431 void win_activeinc(void)
436 void win_activedec(void)
441 int win_activeno(void)
446 /* -------- Giving away the caret. -------- */
448 void win_give_away_caret(void)
450 win__str *ws=win__allwindows;
452 if (ws->w != DUD) { /* found a window */
455 tracef1("get state of window %i.", ws->w);
456 (void) wimp_get_wind_state(ws->w, &s);
457 tracef2("behind=%i flags=%i.\n", s.o.behind, s.flags);
458 if (s.o.behind == DUD && (s.flags & wimp_WOPEN) != 0) {
459 /* w is the top window */
460 /* if it wants the caret, it will grab it. */
461 tracef0("Opening it.\n");
464 wimpt_fake_event(&e);
472 /* ----------- setting a window title ------------ */
474 void win_settitle(wimp_w w, char *newtitle,...)
480 va_start(ap,newtitle);
481 if((winfo = mem_alloc(sizeof(wimp_wind) + 200*sizeof(wimp_icon))) == 0)
483 werr(FALSE, msgs_lookup("win2:Not enough memory to change window title."));
488 tracef1("New title is %s\n", (int)newtitle);
489 /* --- get the window's details --- */
491 wimpt_noerr(wimp_get_wind_info(winfo));
493 /* --- put the new title string in the title icon's buffer --- */
494 tracef1("Lib buffer is at %d\n", (int)winfo->info.title.indirecttext.buffer);
495 vsprintf(winfo->info.title.indirecttext.buffer, newtitle, ap);
498 /* --- invalidate the title bar in absolute coords --- */
499 if (winfo->info.flags & wimp_WOPEN)
501 r.w = (wimp_w) -1; /* absolute screen coords */
502 r.box = winfo->info.box;
503 r.box.y1 += 36; /* yuk - tweaky */
504 r.box.y0 = r.box.y1 - 36;
505 wimpt_noerr(wimp_force_redraw(&r));
508 /* --- free space used to window info --- */
513 * void win_gadgetWidths(wimp_wflags f,wimp_box *b)
516 * Returns a box giving the width of the system area around a window with
520 void win_gadgetWidths(wimp_wflags f,wimp_box *b)
524 {-500,-500,-300,-300},0,0,-1,
539 w.flags=f | wimp_WTRESPASS;
540 if (wimp_create_wind(&w,&temp))
543 b->x1=(f & wimp_WHSCR) ? 40 : 0;
544 b->y0=(f & wimp_WVSCR) ? 40 : 0;
545 b->y1=(f & wimp_WTITLE) ? 40 : 0;
549 wimpt_noerr(wimp_get_wind_state(temp,&s));
550 wimpt_noerr(wimp_open_wind(&s.o));
551 wimpt_noerr(wimp_get_wind_state(temp,&s));
553 wimpt_noerr(wimp_getwindowoutline(&r));
554 b->x0=s.o.box.x0-r.box.x0;
555 b->x1=r.box.x1-s.o.box.x1;
556 b->y1=r.box.y1-s.o.box.y1;
557 b->y0=s.o.box.y0-r.box.y0;
558 wimpt_noerr(wimp_delete_wind(temp));
563 * void win_adjustBox(wimp_openstr *o)
566 * Adjusts a window so that it fits on the screen.
569 * wimp_openstr *o == pointer to the block to fiddle
572 void win_adjustBox(wimp_openstr *o)
574 int scx=wimpt_scwidth();
575 int scy=wimpt_scheight();
576 int w=o->box.x1-o->box.x0;
577 int h=o->box.y1-o->box.y0;
580 wimpt_noerr(wimp_get_wind_state(o->w,&s));
581 win_gadgetWidths(s.flags,&b);
583 if (o->box.x1-o->box.x0>scx-b.x0-b.x1)
588 else if (o->box.x1>scx-b.x1)
591 o->box.x0=scx-b.x1-w;
593 else if (o->box.x0<b.x0)
599 if (o->box.y1-o->box.y0>scy-b.y0-b.y1)
604 else if (o->box.y1>scy-b.y1)
607 o->box.y0=scy-b.y1-h;
609 else if (o->box.y0<b.y0)
617 * BOOL win_anyWindows(void)
620 * Informs the caller if there are any windows left.
626 BOOL win_anyWindows(void)
643 err=wimp_create_wind(&w,&handle);
648 wimp_delete_wind(handle);