1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25   #include "config.h"
26 #endif  // HAVE_CONFIG_H
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 
32 #include <Xm/XmAll.h>
33 
34 #include "xastir.h"
35 #include "main.h"
36 #include "popup.h"
37 #include "main.h"
38 #include "lang.h"
39 #include "rotated.h"
40 #include "snprintf.h"
41 
42 // Must be last include file
43 #include "leak_detection.h"
44 
45 
46 extern XmFontList fontlist1;    // Menu/System fontlist
47 
48 static Popup_Window pw[MAX_POPUPS];
49 static Popup_Window pwb;
50 
51 static xastir_mutex popup_message_dialog_lock;
52 
53 
54 
55 
56 
popup_gui_init(void)57 void popup_gui_init(void)
58 {
59   init_critical_section( &popup_message_dialog_lock );
60 }
61 
62 
63 
64 
65 
66 /**** Popup Message ******/
67 
clear_popup_message_windows(void)68 void clear_popup_message_windows(void)
69 {
70   int i;
71 
72   begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:clear_popup_message_windows" );
73 
74   for (i=0; i<MAX_POPUPS; i++)
75   {
76     pw[i].popup_message_dialog=(Widget)NULL;
77     pw[i].popup_message_data=(Widget)NULL;
78   }
79 
80   end_critical_section(&popup_message_dialog_lock, "popup_gui.c:clear_popup_message_windows" );
81 
82   pwb.popup_message_dialog=(Widget)NULL;
83   pwb.popup_message_data=(Widget)NULL;
84 }
85 
86 
87 
88 
89 
popup_message_destroy_shell(Widget UNUSED (w),XtPointer clientData,XtPointer UNUSED (callData))90 static void popup_message_destroy_shell(Widget UNUSED(w),
91                                         XtPointer clientData,
92                                         XtPointer UNUSED(callData) )
93 {
94   int i;
95 
96   i=atoi((char *)clientData);
97   XtPopdown(pw[i].popup_message_dialog);
98 
99   begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_message_destroy_shell" );
100 
101   XtDestroyWidget(pw[i].popup_message_dialog);
102   pw[i].popup_message_dialog = (Widget)NULL;
103   pw[i].popup_message_data = (Widget)NULL;
104 
105   end_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_message_destroy_shell" );
106 
107 }
108 
109 
110 
111 
112 
113 time_t popup_time_out_check_last = (time_t)0l;
114 
popup_time_out_check(int curr_sec)115 void popup_time_out_check(int curr_sec)
116 {
117   int i;
118 
119   // Check only every two minutes or so
120   if (popup_time_out_check_last + 120 < curr_sec)
121   {
122     popup_time_out_check_last = curr_sec;
123 
124     for (i=0; i<MAX_POPUPS; i++)
125     {
126       if (pw[i].popup_message_dialog!=NULL)
127       {
128         if ((sec_now()-pw[i].sec_opened)>MAX_POPUPS_TIME)
129         {
130           XtPopdown(pw[i].popup_message_dialog);
131 
132           begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" );
133 
134           XtDestroyWidget(pw[i].popup_message_dialog);
135           pw[i].popup_message_dialog = (Widget)NULL;
136           pw[i].popup_message_data = (Widget)NULL;
137 
138           end_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" );
139 
140         }
141 
142       }
143     }
144   }
145 }
146 
147 
148 
149 
150 
popup_message_always(char * banner,char * message)151 void popup_message_always(char *banner, char *message)
152 {
153   XmString msg_str;
154   int j,i;
155   Atom delw;
156 
157 
158   if (disable_all_popups)
159   {
160     return;
161   }
162 
163   if (banner == NULL || message == NULL)
164   {
165     return;
166   }
167 
168   i=0;
169   for (j=0; j<MAX_POPUPS; j++)
170   {
171     if (!pw[j].popup_message_dialog)
172     {
173       i=j;
174       j=MAX_POPUPS+1;
175     }
176   }
177 
178   if(!pw[i].popup_message_dialog)
179   {
180     if (banner!=NULL && message!=NULL)
181     {
182 
183       begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_message" );
184 
185       pw[i].popup_message_dialog = XtVaCreatePopupShell(banner,
186                                    xmDialogShellWidgetClass, appshell,
187                                    XmNdeleteResponse, XmDESTROY,
188                                    XmNdefaultPosition, FALSE,
189                                    XmNtitleString,banner,
190 // An half-hearted attempt at fixing the problem where a popup
191 // comes up extremely small.  Setting a minimum size for the popup.
192                                    XmNminWidth, 220,
193                                    XmNminHeight, 80,
194                                    XmNfontList, fontlist1,
195                                    NULL);
196 
197       pw[i].pane = XtVaCreateWidget("popup_message pane",xmPanedWindowWidgetClass, pw[i].popup_message_dialog,
198                                     XmNbackground, colors[0xff],
199                                     NULL);
200 
201       pw[i].scrollwindow = XtVaCreateManagedWidget("scrollwindow",
202                                                    xmScrolledWindowWidgetClass,
203                                                    pw[i].pane,
204                                                    XmNscrollingPolicy, XmAUTOMATIC,
205                                                    NULL);
206 
207       pw[i].form =  XtVaCreateWidget("popup_message form",
208                                      xmFormWidgetClass,
209                                      pw[i].scrollwindow,
210                                      XmNfractionBase, 5,
211                                      XmNbackground, colors[0xff],
212                                      XmNautoUnmanage, FALSE,
213                                      XmNshadowThickness, 1,
214                                      NULL);
215 
216       pw[i].popup_message_data = XtVaCreateManagedWidget("popup_message message",xmLabelWidgetClass, pw[i].form,
217                                  XmNtopAttachment, XmATTACH_FORM,
218                                  XmNtopOffset, 10,
219                                  XmNbottomAttachment, XmATTACH_NONE,
220                                  XmNleftAttachment, XmATTACH_FORM,
221                                  XmNleftOffset, 10,
222                                  XmNrightAttachment, XmATTACH_FORM,
223                                  XmNrightOffset, 10,
224                                  XmNbackground, colors[0xff],
225                                  XmNfontList, fontlist1,
226                                  NULL);
227 
228       pw[i].button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, pw[i].form,
229                            XmNtopAttachment, XmATTACH_WIDGET,
230                            XmNtopWidget, pw[i].popup_message_data,
231                            XmNtopOffset, 10,
232                            XmNbottomAttachment, XmATTACH_FORM,
233                            XmNbottomOffset, 5,
234                            XmNleftAttachment, XmATTACH_POSITION,
235                            XmNleftPosition, 2,
236                            XmNrightAttachment, XmATTACH_POSITION,
237                            XmNrightPosition, 3,
238                            XmNbackground, colors[0xff],
239                            XmNfontList, fontlist1,
240                            NULL);
241 
242       xastir_snprintf(pw[i].name,10,"%9d",i%1000);
243 
244       msg_str=XmStringCreateLtoR(message,XmFONTLIST_DEFAULT_TAG);
245       XtVaSetValues(pw[i].popup_message_data,XmNlabelString,msg_str,NULL);
246       XmStringFree(msg_str);
247 
248       XtAddCallback(pw[i].button_close, XmNactivateCallback, popup_message_destroy_shell,(XtPointer)pw[i].name);
249 
250       delw = XmInternAtom(XtDisplay(pw[i].popup_message_dialog),"WM_DELETE_WINDOW", FALSE);
251 
252       XmAddWMProtocolCallback(pw[i].popup_message_dialog, delw, popup_message_destroy_shell, (XtPointer)pw[i].name);
253 
254       pos_dialog(pw[i].popup_message_dialog);
255 
256       XtManageChild(pw[i].form);
257       XtManageChild(pw[i].pane);
258 
259       resize_dialog(pw[i].form, pw[i].popup_message_dialog);
260 
261       end_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_message" );
262 
263       XtPopup(pw[i].popup_message_dialog,XtGrabNone);
264 
265       pw[i].sec_opened=sec_now();
266     }
267   }
268 }
269 
270 
271 
272 
273 
274 #ifndef HAVE_ERROR_POPUPS
275 //
276 // We'll write to STDERR instead since the user doesn't want to see
277 // any error popups.  Add a timestamp to the front so we know when
278 // the errors happened.
279 //
popup_message(char * banner,char * message)280 void popup_message(char *banner, char *message)
281 {
282   char timestring[110];
283 
284 
285   if (disable_all_popups)
286   {
287     return;
288   }
289 
290   if (banner == NULL || message == NULL)
291   {
292     return;
293   }
294 
295   get_timestamp(timestring);
296   fprintf(stderr, "%s:\n\t%s  %s\n\n", timestring, banner, message);
297 }
298 #else   // HAVE_ERROR_POPUPS
299 //
300 // The user wishes to see popup error messages.  Call the routine
301 // above which does so.
302 //
popup_message(char * banner,char * message)303 void popup_message(char *banner, char *message)
304 {
305   popup_message_always(banner, message);
306 }
307 #endif  // HAVE_ERROR_POPUPS
308 
309 
310 
311 
312 
313 
314 // Must make sure that fonts are not loaded again and again, as this
315 // takes a big chunk of memory each time.  Can you say "memory
316 // leak"?
317 //
318 static XFontStruct *id_font=NULL;
319 
320 
321 
322 
323 
324 // Routine which pops up a large message for a few seconds in the
325 // middle of the screen, then removes it.
326 //
popup_ID_message(char * UNUSED (banner),char * message)327 void popup_ID_message(char * UNUSED(banner), char *message)
328 {
329   float my_rotation = 0.0;
330   int x = (int)(screen_width/10);
331   int y = (int)(screen_height/2);
332 
333   if (ATV_screen_ID)
334   {
335 
336     // Fill the pixmap with grey so that the black ID text will
337     // be seen.
338     (void)XSetForeground(XtDisplay(da),gc,MY_BG_COLOR); // Not a mistake!
339     (void)XSetBackground(XtDisplay(da),gc,MY_BG_COLOR);
340     (void)XFillRectangle(XtDisplay(appshell),
341                          pixmap_alerts,
342                          gc,
343                          0,
344                          0,
345                          (unsigned int)screen_width,
346                          (unsigned int)screen_height);
347 
348     /* load font */
349     if(!id_font)
350     {
351       id_font=(XFontStruct *)XLoadQueryFont (XtDisplay(da), rotated_label_fontname[FONT_ATV_ID]);
352 
353       if (id_font == NULL)      // Couldn't get the font!!!
354       {
355         fprintf(stderr,"popup_ID_message: Couldn't get ATV ID font %s\n",
356                 rotated_label_fontname[FONT_ATV_ID]);
357         pending_ID_message = 0;
358         return;
359       }
360     }
361 
362     (void)XSetForeground (XtDisplay(da), gc, colors[0x08]);
363 
364     //fprintf(stderr,"%0.1f\t%s\n",my_rotation,label_text);
365 
366     if (       ( (my_rotation < -90.0) && (my_rotation > -270.0) )
367                || ( (my_rotation >  90.0) && (my_rotation <  270.0) ) )
368     {
369       my_rotation = my_rotation + 180.0;
370       (void)XRotDrawAlignedString(XtDisplay(da),
371                                   id_font,
372                                   my_rotation,
373                                   pixmap_alerts,
374                                   gc,
375                                   x,
376                                   y,
377                                   message,
378                                   BRIGHT);
379     }
380     else
381     {
382       (void)XRotDrawAlignedString(XtDisplay(da),
383                                   id_font,
384                                   my_rotation,
385                                   pixmap_alerts,
386                                   gc,
387                                   x,
388                                   y,
389                                   message,
390                                   BLEFT);
391     }
392 
393     // Schedule a screen update in roughly 3 seconds
394     remove_ID_message_time = sec_now() + 3;
395     pending_ID_message = 1;
396 
397     // Write it to the screen.  Symbols/tracks will disappear during
398     // this short interval time.
399     (void)XCopyArea(XtDisplay(da),
400                     pixmap_alerts,
401                     XtWindow(da),
402                     gc,
403                     0,
404                     0,
405                     (unsigned int)screen_width,
406                     (unsigned int)screen_height,
407                     0,
408                     0);
409   }
410   else    // ATV Screen ID is not enabled
411   {
412     pending_ID_message = 0;
413   }
414 }
415 
416 
417