1 
2 /******************************************************************************
3 * MODULE     : x_gui.cpp
4 * DESCRIPTION: Graphical user interface for X11
5 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "timer.hpp"
13 #include "dictionary.hpp"
14 #include "X11/x_gui.hpp"
15 #include "X11/x_drawable.hpp"
16 #include "X11/x_window.hpp"
17 #include "image_files.hpp"
18 #include <X11/cursorfont.h>
19 #include "message.hpp"
20 #include "x_picture.hpp"
21 
22 extern hashmap<Window,pointer> Window_to_window;
23 
24 /******************************************************************************
25 * Making color scales for anti alised fonts
26 ******************************************************************************/
27 
x_character_rep(int c2,font_glyphs fng2,int sf2,color fg2,color bg2)28 x_character_rep::x_character_rep (
29   int c2, font_glyphs fng2, int sf2, color fg2, color bg2):
30     c (c2), fng (fng2), sf (sf2), fg (fg2), bg (bg2) {}
31 
x_character(int c,font_glyphs fng,int sf,color fg,color bg)32 x_character::x_character (int c, font_glyphs fng, int sf, color fg, color bg):
33   rep (tm_new<x_character_rep> (c, fng, sf, fg, bg)) {}
34 
operator tree()35 x_character::operator tree () {
36   tree t (TUPLE,  as_string (rep->c), rep->fng->res_name);
37   t << as_string (rep->sf) << as_string (rep->fg) << as_string (rep->bg);
38   return t; }
39 
operator ==(x_character xc1,x_character xc2)40 bool operator == (x_character xc1, x_character xc2) {
41   return
42     (xc1->c==xc2->c) && (xc1->fng.rep==xc2->fng.rep) &&
43     (xc1->sf==xc2->sf) && (xc1->fg==xc2->fg) && (xc1->bg==xc2->bg); }
44 
operator !=(x_character xc1,x_character xc2)45 bool operator != (x_character xc1, x_character xc2) {
46   return
47     (xc1->c!=xc2->c) || (xc1->fng.rep!=xc2->fng.rep) ||
48     (xc1->sf!=xc2->sf) || (xc1->fg!=xc2->fg) || (xc1->bg!=xc2->bg); }
49 
hash(x_character xc)50 int hash (x_character xc) {
51   return xc->c ^ ((intptr_t) xc->fng.rep) ^ xc->fg ^ xc->bg ^ xc->sf; }
52 
53 void
prepare_color(int sf,color fg,color bg)54 x_gui_rep::prepare_color (int sf, color fg, color bg) {
55   int nr_cols= sf*sf;
56   if (nr_cols >= 64) nr_cols= 64;
57   x_character col_entry (0, font_glyphs (), sf, fg, bg);
58   color* cols= (color*) color_scale [col_entry];
59   if (cols == NULL) {
60     int fR, fG, fB, fA, bR, bG, bB, bA, j;
61     get_rgb_color (fg, fR, fG, fB, fA);
62     get_rgb_color (bg, bR, bG, bB, bA);
63     if (fA != 255) {
64       fR= (bR * (255 - fA) + fR * fA) / 255;
65       fG= (bG * (255 - fA) + fG * fA) / 255;
66       fB= (bB * (255 - fA) + fB * fA) / 255;
67     }
68     cols= tm_new_array<color> (nr_cols+1);
69     for (j=0; j<=nr_cols; j++)
70       cols [nr_cols-j]= rgb_color ((bR*j + fR*(nr_cols-j)) / nr_cols,
71 				   (bG*j + fG*(nr_cols-j)) / nr_cols,
72 				   (bB*j + fB*(nr_cols-j)) / nr_cols);
73     color_scale (col_entry)= (void*) cols;
74   }
75 }
76 
77 /******************************************************************************
78 * Subroutines
79 ******************************************************************************/
80 
81 void
set_button_state(unsigned int state)82 x_gui_rep::set_button_state (unsigned int state) {
83   int i= 0;
84   if ((state & Button1Mask) != 0) i += 1;
85   if ((state & Button2Mask) != 0) i += 2;
86   if ((state & Button3Mask) != 0) i += 4;
87   if ((state & Button4Mask) != 0) i += 8;
88   if ((state & Button5Mask) != 0) i += 16;
89   if ((state & ShiftMask)   != 0) i += 256;
90   if ((state & ControlMask) != 0) i += 512;
91   if ((state & LockMask)    != 0) i += 1024;
92   if ((state & Mod1Mask)    != 0) i += 2048;
93   if ((state & Mod2Mask)    != 0) i += 4096;
94   if ((state & Mod3Mask)    != 0) i += 8192;
95   if ((state & Mod4Mask)    != 0) i += 16384;
96   if ((state & Mod5Mask)    != 0) i += 32768;
97   x_gui_rep::state= i;
98 }
99 
100 void
emulate_leave_enter(widget old_widget,widget new_widget)101 x_gui_rep::emulate_leave_enter (widget old_widget, widget new_widget) {
102   Window root, child;
103   SI root_x, root_y, x, y;
104   unsigned int mask;
105 
106   XQueryPointer (dpy, get_Window (old_widget),
107 		 &root, &child, &root_x, &root_y, &x, &y, &mask);
108   set_button_state (mask);
109   x= (x * PIXEL);
110   y= ((-y) * PIXEL);
111   // cout << "\nLeave " << old_widget << "\n";
112   send_mouse (old_widget, "leave", x, y, state, 0);
113   // cout << "Leave OK\n";
114 
115   XQueryPointer (dpy, get_Window (new_widget),
116 		 &root, &child, &root_x, &root_y, &x, &y, &mask);
117   set_button_state (mask);
118   x= (x * PIXEL);
119   y= ((-y) * PIXEL);
120   // cout << "Enter " << new_widget << "\n";
121   send_mouse (new_widget, "enter", x, y, state, 0);
122   // cout << "Enter OK\n\n";
123 }
124 
125 /******************************************************************************
126 * Grabbing
127 ******************************************************************************/
128 
129 /*
130 string
131 pritty (tree t) {
132   if (is_atomic (t)) return copy (as_string (t));
133   else if (N(t) == 2) return pritty (t[1]);
134   else {
135     int i;
136     string s ("(");
137     for (i=1; i<N(t); i++) {
138       if (i>1) s << " ";
139       s << pritty (t[i]);
140     }
141     s << ")";
142     return s;
143   }
144 }
145 */
146 
147 void
obtain_mouse_grab(widget wid)148 x_gui_rep::obtain_mouse_grab (widget wid) {
149   Window win= get_Window (wid);
150   if ((!is_nil (grab_ptr)) && (wid==grab_ptr->item)) return;
151   widget old_widget; if (!is_nil (grab_ptr)) old_widget= grab_ptr->item;
152   grab_ptr= list<widget> (wid, grab_ptr);
153   widget new_widget= grab_ptr->item;
154   notify_mouse_grab (new_widget, true);
155   XGrabPointer (dpy, win, false,
156 		PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
157 		GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
158   // cout << "\n---> In grab " << pritty ((tree) wid) << "\n\n";
159   if (!is_nil (old_widget)) {
160     notify_mouse_grab (old_widget, false);
161     emulate_leave_enter (old_widget, new_widget);
162   }
163 }
164 
165 void
release_mouse_grab()166 x_gui_rep::release_mouse_grab () {
167   if (is_nil (grab_ptr)) return;
168   widget old_widget= grab_ptr->item;
169   grab_ptr= grab_ptr->next;
170   widget new_widget; if (!is_nil (grab_ptr)) new_widget= grab_ptr->item;
171   if (is_nil (grab_ptr)) {
172     XUngrabPointer (dpy, CurrentTime);
173     // cout << "\n---> No grab\n\n";
174   }
175   else {
176     x_window grab_win= get_x_window (new_widget);
177     notify_mouse_grab (new_widget, true);
178     XGrabPointer (dpy, grab_win->win, false,
179 		  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
180 		  GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
181     // cout << "\n---> In grab " << new_widget << "\n";
182     notify_mouse_grab (old_widget, false);
183     emulate_leave_enter (old_widget, new_widget);
184   }
185 }
186 
187 bool
has_mouse_grab(widget w)188 x_gui_rep::has_mouse_grab (widget w) {
189   return (!is_nil (grab_ptr)) && (grab_ptr->item == w);
190 }
191 
192 /******************************************************************************
193 * Selections
194 ******************************************************************************/
195 
196 Bool
my_selnotify_predicate(Display * dpy,XEvent * ev,XPointer arg)197 my_selnotify_predicate (Display* dpy, XEvent* ev, XPointer arg) { (void) dpy;
198   x_window win= (x_window) arg;
199   return (win->win==ev->xany.window) && (ev->type==SelectionNotify);
200 }
201 
202 void
created_window(Window win)203 x_gui_rep::created_window (Window win) {
204   windows_l << win;
205 }
206 
207 void
deleted_window(Window win)208 x_gui_rep::deleted_window (Window win) {
209   windows_l= remove (windows_l, win);
210 }
211 
212 void
focussed_window(Window win)213 x_gui_rep::focussed_window (Window win) {
214   windows_l= list<Window> (win, remove (windows_l, win));
215 }
216 
217 bool
get_selection(string key,tree & t,string & s)218 x_gui_rep::get_selection (string key, tree& t, string& s) {
219   t= "none";
220   s= "";
221   bool res=false;
222 
223   if (selection_t->contains (key)) {
224     t= copy (selection_t [key]);
225     s= copy (selection_s [key]);
226     return true;
227   }
228 
229   Atom xsel;
230   if (key == "primary") xsel = XA_CLIPBOARD;
231   else if (key == "mouse") xsel = XA_PRIMARY;
232   else return res;
233 
234   Window selown = XGetSelectionOwner(dpy, xsel);
235   if (selown == None ||
236       is_nil (windows_l) ||
237       contains (windows_l, selown)) return res;
238 
239   Window win= windows_l->item;
240   x_window x_win= (x_window) Window_to_window[win];
241   Atom prop= XInternAtom (dpy, "MY_STRING_SELECTION", false);
242   XConvertSelection (dpy, xsel, XA_STRING, prop, win, CurrentTime);
243 
244   int i;
245   XEvent ev;
246   for (i=0; i<1000000; i++)
247     if (XCheckIfEvent (dpy, &ev, my_selnotify_predicate, (XPointer) x_win))
248       break;
249   if (i==1000000) return res;
250   XSelectionEvent& sel= ev.xselection;
251 
252   if (sel.property==prop) {
253     long offset=0;
254     Atom type;
255     int fm;
256     unsigned long n, remains;
257     unsigned char* ret;
258 
259     do {
260       XGetWindowProperty (dpy, win, sel.property,
261 			  offset, 1024, true, AnyPropertyType,
262 			  &type, &fm, &n, &remains, &ret);
263       s << string ((char*) ret, n);
264       offset += (n >> 2);
265       XFree (ret);
266     } while (remains>0);
267     t= tuple ("extern", s);
268     return true;
269   }
270   else return res;
271 }
272 
273 bool
set_selection(string key,tree t,string s)274 x_gui_rep::set_selection (string key, tree t, string s) {
275   selection_t (key)= copy (t);
276   selection_s (key)= copy (s);
277   Atom xsel;
278   if(key == "primary") xsel = XA_CLIPBOARD;
279   else if (key == "mouse") xsel = XA_PRIMARY;
280   else return true;
281   if (is_nil (windows_l)) return false;
282   Window win= windows_l->item;
283   selection_w= win;
284   XSetSelectionOwner (dpy, xsel, win, CurrentTime);
285   if (XGetSelectionOwner (dpy, xsel) == None) return false;
286   return true;
287 }
288 
289 void
clear_selection(string key)290 x_gui_rep::clear_selection (string key) {
291   selection_t->reset (key);
292   selection_s->reset (key);
293 }
294 
295 bool
set_selection(string key,tree t,string s,string sv,string sh,string format)296 set_selection (string key, tree t,
297                string s, string sv, string sh, string format) {
298   (void) format;
299   return the_gui->set_selection (key, t, s);
300 }
301 
302 bool
get_selection(string key,tree & t,string & s,string format)303 get_selection (string key, tree& t, string& s, string format) {
304   (void) format;
305   return the_gui->get_selection (key, t, s);
306 }
307 
308 void
clear_selection(string key)309 clear_selection (string key) {
310   the_gui->clear_selection (key);
311 }
312 
313 /******************************************************************************
314 * X Pointers
315 ******************************************************************************/
316 
317 // Definitions from X11/cursorfont.h
318 static int
fetch_X11_cursor_no(string name)319 fetch_X11_cursor_no (string name) {
320   string pref= name(0,3);
321   if (pref!="XC_") return -1;
322   name= name (3,N(name));
323   switch (name[0]) {
324     case 'X':
325       if (name=="X_cursor") return XC_X_cursor;
326     break;
327     case 'a':
328       if (name=="arrow") return XC_arrow;
329     break;
330     case 'b':
331       if (name=="based_arrow_down") return XC_based_arrow_down;
332       if (name=="based_arrow_up") return XC_based_arrow_up;
333       if (name=="boat") return XC_boat;
334       if (name=="bogosity") return XC_bogosity;
335       if (name=="bottom_left_corner") return XC_bottom_left_corner;
336       if (name=="bottom_right_corner") return XC_bottom_right_corner;
337       if (name=="bottom_side") return XC_bottom_side;
338       if (name=="bottom_tee") return XC_bottom_tee;
339       if (name=="box_spiral") return XC_box_spiral;
340     break;
341     case 'c':
342       if (name=="center_ptr") return XC_center_ptr;
343       if (name=="circle") return XC_circle;
344       if (name=="clock") return XC_clock;
345       if (name=="coffee_mug") return XC_coffee_mug;
346       if (name=="cross") return XC_cross;
347       if (name=="cross_reverse") return XC_cross_reverse;
348       if (name=="crosshair") return XC_crosshair;
349     break;
350     case 'd':
351       if (name=="diamond_cross") return XC_diamond_cross;
352       if (name=="dot") return XC_dot;
353       if (name=="dotbox") return XC_dotbox;
354       if (name=="double_arrow") return XC_double_arrow;
355       if (name=="draft_large") return XC_draft_large;
356       if (name=="draft_small") return XC_draft_small;
357       if (name=="draped_box") return XC_draped_box;
358     break;
359     case 'e':
360       if (name=="exchange") return XC_exchange;
361     break;
362     case 'f':
363       if (name=="fleur") return XC_fleur;
364     break;
365     case 'g':
366       if (name=="gobbler") return XC_gobbler;
367       if (name=="gumby") return XC_gumby;
368     break;
369     case 'h':
370       if (name=="hand1") return XC_hand1;
371       if (name=="hand2") return XC_hand2;
372       if (name=="heart") return XC_heart;
373     break;
374     case 'i':
375       if (name=="icon") return XC_icon;
376       if (name=="iron_cross") return XC_iron_cross;
377     break;
378     case 'l':
379       if (name=="left_ptr") return XC_left_ptr;
380       if (name=="left_side") return XC_left_side;
381       if (name=="left_tee") return XC_left_tee;
382       if (name=="leftbutton") return XC_leftbutton;
383       if (name=="ll_angle") return XC_ll_angle;
384       if (name=="lr_angle") return XC_lr_angle;
385     break;
386     case 'm':
387       if (name=="man") return XC_man;
388       if (name=="middlebutton") return XC_middlebutton;
389       if (name=="mouse") return XC_mouse;
390     break;
391     case 'p':
392       if (name=="pencil") return XC_pencil;
393       if (name=="pirate") return XC_pirate;
394       if (name=="plus") return XC_plus;
395     break;
396     case 'q':
397       if (name=="question_arrow") return XC_question_arrow;
398     break;
399     case 'r':
400       if (name=="right_ptr") return XC_right_ptr;
401       if (name=="right_side") return XC_right_side;
402       if (name=="right_tee") return XC_right_tee;
403       if (name=="rightbutton") return XC_rightbutton;
404       if (name=="rtl_logo") return XC_rtl_logo;
405     break;
406     case 's':
407       if (name=="sailboat") return XC_sailboat;
408       if (name=="sb_down_arrow") return XC_sb_down_arrow;
409       if (name=="sb_h_double_arrow") return XC_sb_h_double_arrow;
410       if (name=="sb_left_arrow") return XC_sb_left_arrow;
411       if (name=="sb_right_arrow") return XC_sb_right_arrow;
412       if (name=="sb_up_arrow") return XC_sb_up_arrow;
413       if (name=="sb_v_double_arrow") return XC_sb_v_double_arrow;
414       if (name=="shuttle") return XC_shuttle;
415       if (name=="sizing") return XC_sizing;
416       if (name=="spider") return XC_spider;
417       if (name=="spraycan") return XC_spraycan;
418       if (name=="star") return XC_star;
419     break;
420     case 't':
421       if (name=="target") return XC_target;
422       if (name=="tcross") return XC_tcross;
423       if (name=="top_left_arrow") return XC_top_left_arrow;
424       if (name=="top_left_corner") return XC_top_left_corner;
425       if (name=="top_right_corner") return XC_top_right_corner;
426       if (name=="top_side") return XC_top_side;
427       if (name=="top_tee") return XC_top_tee;
428       if (name=="trek") return XC_trek;
429     break;
430     case 'u':
431       if (name=="ul_angle") return XC_ul_angle;
432       if (name=="umbrella") return XC_umbrella;
433       if (name=="ur_angle") return XC_ur_angle;
434     break;
435     case 'w':
436       if (name=="watch") return XC_watch;
437     break;
438     case 'x':
439       if (name=="xterm") return XC_xterm;
440     break;
441   }
442   return -1;
443 }
444 
445 void
set_mouse_pointer(widget w,string name)446 x_gui_rep::set_mouse_pointer (widget w, string name) {
447   int no= fetch_X11_cursor_no (name);
448   if (no==-1) return;
449   Cursor cursor=XCreateFontCursor(dpy, no);
450   x_window win= get_x_window (w);
451   if (win != NULL) XDefineCursor(dpy, win->win, cursor);
452 }
453 
454 void
set_mouse_pointer(widget w,string name,string mask_name)455 x_gui_rep::set_mouse_pointer (widget w, string name, string mask_name) {
456   static hashmap<string,tree> xpm_cache ("");
457   if (mask_name=="") mask_name= name;
458   Pixmap curs= retrieve_bitmap (load_xpm (name));
459   Pixmap mask= retrieve_bitmap (load_xpm (mask_name));
460 
461   if (!xpm_cache->contains (name))
462     xpm_cache (name)= xpm_load (name);
463 
464   if (!xpm_cache->contains (mask_name))
465     xpm_cache (mask_name)= xpm_load (mask_name);
466 
467   array<string> cnames_curs= xpm_colors (xpm_cache[name]);
468   array<SI> hotspot= xpm_hotspot (xpm_cache[name]);
469   ASSERT (N(hotspot) != 0, "missing hotspot");
470   array<string> cnames_mask= xpm_colors (xpm_cache[mask_name]);
471   c_string bgcolor (N(cnames_mask)>1 ? cnames_mask[1]: string ("white"));
472   c_string fgcolor (N(cnames_curs)>1 ? cnames_curs[1]: string ("black"));
473   if (!strcmp (bgcolor, "none")) bgcolor= c_string (string ("white"));
474   if (!strcmp (fgcolor, "none")) fgcolor= c_string (string ("white"));
475 
476   XColor *bg= NULL, *fg= NULL;
477   XColor exact1, closest1;
478   XLookupColor(dpy, cols, fgcolor, &exact1, &closest1);
479   if (XAllocColor (dpy, cols, &exact1)) fg= &exact1;
480   else if (XAllocColor (dpy, cols, &closest1)) fg= &closest1;
481   else FAILED ("unable to allocate fgcolor");
482 
483   XColor exact2, closest2;
484   XLookupColor(dpy, cols, bgcolor, &exact2, &closest2);
485   if (XAllocColor (dpy, cols, &exact2)) bg= &exact2;
486   else if (XAllocColor (dpy, cols, &closest2)) bg= &closest2;
487   else FAILED ("unable to allocate bgcolor");
488 
489   SI x= hotspot[0], y= hotspot[1];
490   Cursor cursor=XCreatePixmapCursor (dpy, curs, mask, fg, bg, x, y);
491   x_window win= get_x_window (w);
492   if (win != NULL) XDefineCursor(dpy, win->win, cursor);
493 }
494 
495 /******************************************************************************
496 * Miscellaneous
497 ******************************************************************************/
498 
499 void
show_help_balloon(widget wid,SI x,SI y)500 x_gui_rep::show_help_balloon (widget wid, SI x, SI y) {
501   unmap_balloon ();
502   balloon_wid = wid;
503   balloon_win = NULL;
504   balloon_x   = x;
505   balloon_y   = y;
506   balloon_time= texmacs_time ();
507 }
508 
509 void
map_balloon()510 x_gui_rep::map_balloon () {
511   widget win_wid= popup_window_widget (balloon_wid, "Balloon");
512   set_position (win_wid, balloon_x, balloon_y);
513   balloon_win= (window) get_x_window (win_wid);
514   balloon_win->set_visibility (true);
515 }
516 
517 void
unmap_balloon()518 x_gui_rep::unmap_balloon () {
519   if (!is_nil (balloon_wid)) {
520     if (balloon_win != NULL) {
521       balloon_win->set_visibility (false);
522       tm_delete (balloon_win);
523       balloon_win= NULL;
524     }
525     balloon_wid= widget ();
526   }
527 }
528 
529 void
show_wait_indicator(widget w,string message,string arg)530 x_gui_rep::show_wait_indicator (widget w, string message, string arg) {
531   // NOTE: the wait indicator is directly displayed inside the window
532   // corresponding to w. We explicitly shortcut the main event loop
533   // by invalidating the wait widget and requesting a redraw.
534   // Using a popup window does not work, because it would be necessary
535   // to return to the main loop to map and redraw it.
536   x_window ww= get_x_window (w);
537   if (ww == NULL || message == "") return;
538   if (arg != "") message= message * " " * arg * "...";
539   SI width= 400*PIXEL, height= 160*PIXEL;
540   widget wait_wid= wait_widget (width, height, message);
541   SI mid_x= (ww->win_w>>1)*PIXEL, mid_y= -(ww->win_h>>1)*PIXEL + height;
542   SI x= mid_x- width/2, y= mid_y- height/2;
543   widget old_wid= ww->w;
544   ww->w= wait_wid;
545   set_position (wait_wid, x, y);
546   set_identifier (wait_wid, (int) ww->win);
547   send_invalidate_all (wait_wid);
548   ww->repaint_invalid_regions ();
549   ww->w= old_wid;
550   XFlush (dpy);
551   send_invalidate_all (old_wid);
552 }
553 
554 void
external_event(string type,time_t t)555 x_gui_rep::external_event (string type, time_t t) {
556   (void) t;
557   if (!is_nil (windows_l)) {
558     Window win= windows_l->item;
559     x_window x_win= (x_window) Window_to_window[win];
560     x_win->key_event (type);
561   }
562 }
563 
564 bool
check_event(int type)565 x_gui_rep::check_event (int type) {
566   bool status;
567   XEvent ev;
568   switch (type) {
569   case INTERRUPT_EVENT:
570     if (interrupted) return true;
571     else {
572       time_t now= texmacs_time ();
573       if (now - interrupt_time < 0) return false;
574       else interrupt_time= now + (100 / (XPending (dpy) + 1));
575       interrupted= XCheckMaskEvent (dpy, KeyPressMask|ButtonPressMask, &ev);
576       if (interrupted) XPutBackEvent (dpy, &ev);
577       return interrupted;
578     }
579   case INTERRUPTED_EVENT:
580     return interrupted;
581   case ANY_EVENT:
582     return (XPending (dpy)>0);
583   case MOTION_EVENT:
584     status= XCheckMaskEvent (dpy, PointerMotionMask, &ev);
585     if (status) XPutBackEvent (dpy, &ev);
586     return status;
587   case DRAG_EVENT:
588     status= XCheckMaskEvent (dpy, ButtonMotionMask, &ev);
589     if (status) XPutBackEvent (dpy, &ev);
590     return status;
591   case MENU_EVENT:
592     status= XCheckMaskEvent (dpy, ButtonMotionMask|ButtonReleaseMask, &ev);
593     if (status) XPutBackEvent (dpy, &ev);
594     return status;
595   }
596   return interrupted;
597 }
598 
599 void
beep()600 beep () {
601 #ifdef OS_WIN32
602   XBeep ();
603 #else
604   cerr << '\a';
605 #endif
606 }
607 
608 void
show_help_balloon(widget wid,SI x,SI y)609 show_help_balloon (widget wid, SI x, SI y) {
610   the_gui->show_help_balloon (wid, x, y);
611 }
612 
613 void
show_wait_indicator(widget w,string message,string arg)614 show_wait_indicator (widget w, string message, string arg) {
615   the_gui->show_wait_indicator (w, message, arg);
616 }
617 
618 void
external_event(string type,time_t t)619 external_event (string type, time_t t) {
620   the_gui->external_event (type, t);
621 }
622 
623 void
needs_update()624 needs_update () {
625 }
626 
627 bool
check_event(int type)628 check_event (int type) {
629   return the_gui->check_event (type);
630 }
631 
632 bool
gui_interrupted(bool check)633 gui_interrupted (bool check) {
634   return check_event (check? INTERRUPT_EVENT: INTERRUPTED_EVENT);
635 }
636 
637 
638