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