appkit  1.5.1
RoadNarrows Robotics Application Kit
WinGtkMsg.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Application Tool Kit
4 //
5 // Library: librnr_wingtk
6 //
7 // File: WinGtkMsg.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2013-05-03 07:45:13 -0600 (Fri, 03 May 2013) $
12  * $Rev: 2904 $
13  *
14  * \brief GTK dialog and status windowing functions.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  * \author Daniel Packard (daniel@roadnarrows.com)
18  *
19  * \par Copyright
20  * \h_copy 2011-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Permission is hereby granted, without written agreement and without
28  * license or royalty fees, to use, copy, modify, and distribute this
29  * software and its documentation for any purpose, provided that
30  * (1) The above copyright notice and the following two paragraphs
31  * appear in all copies of the source code and (2) redistributions
32  * including binaries reproduces these notices in the supporting
33  * documentation. Substantial modifications to this software may be
34  * copyrighted by their authors and need not follow the licensing terms
35  * described here, provided that the new terms are clearly indicated in
36  * all files where they apply.
37  *
38  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
39  * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
40  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
41  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
42  * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
43  * THE POSSIBILITY OF SUCH DAMAGE.
44  *
45  * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
46  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
47  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
48  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
49  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
50  *
51  * @EulaEnd@
52  */
53 ////////////////////////////////////////////////////////////////////////////////
54 
55 #include <sys/types.h>
56 #include <stdarg.h>
57 #include <libgen.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 
61 #undef IT_TIMER ///< use gtk timer instead
62 
63 #ifdef IT_TIMER
64 #include <signal.h>
65 #include <time.h>
66 #endif // IT_TIMER
67 
68 #include <cstring>
69 #include <iostream>
70 #include <fstream>
71 #include <cmath>
72 
73 #include "rnr/rnrconfig.h"
74 #include "rnr/log.h"
75 
76 #include "opencv2/core/core.hpp"
77 #include "opencv/highgui/highgui.hpp"
78 
79 #include <gtk/gtk.h>
80 
81 #include "rnr/appkit/Win.h"
82 
83 
84 using namespace std;
85 using namespace rnrWin;
86 
87 
88 // ----------------------------------------------------------------------------
89 // Private Interface
90 // ----------------------------------------------------------------------------
91 
92 static GtkWidget *SBWidget = NULL; ///< status bar gtk widget
93 static bool SBIsVisible = false; ///< status bar is [not] visible
94 static GtkWindow *SBWindow = NULL; ///< status bar gtk window
95 static GtkWidget *SBLabelWidget = NULL; ///< status bar label gtk widget
96 static CvRect SBWinGeom = {0, }; ///< status bar window geometry
97 
98 #ifdef IT_TIMER
99 static timer_t SBTimerId = NULL; ///< status bar timer
100 
101 #define SB_CLOCKID CLOCK_REALTIME ///< status bar clock id
102 #define SB_SIG SIGRTMIN ///< status bar timer signal
103 
104 /*!
105  * \brief Status Bar timer handler.
106  *
107  * \param sig Received signal.
108  * \param si Signal information.
109  * \param uc User data
110  */
111 static void SBTimerHandler(int sig, siginfo_t *si, void *uc)
112 {
113  StatusClear();
114 }
115 
116 /*!
117  * \brief Create Status Bar timer.
118  */
119 static void SBTimerCreate()
120 {
121  struct sigevent sev;
122  long long freq_nanosecs;
123  sigset_t mask;
124  struct sigaction sa;
125 
126  // establish handler for timer signal
127  sa.sa_flags = SA_SIGINFO;
128  sa.sa_sigaction = SBTimerHandler;
129  sigemptyset(&sa.sa_mask);
130  if( sigaction(SB_SIG, &sa, NULL) == -1 )
131  {
132  LOGSYSERROR("Cannot set Status Bar signal action: sigaction()");
133  }
134 
135  // create the timer
136  sev.sigev_notify = SIGEV_SIGNAL;
137  sev.sigev_signo = SB_SIG;
138  sev.sigev_value.sival_ptr = &SBTimerId;
139  if( timer_create(SB_CLOCKID, &sev, &SBTimerId) == -1 )
140  {
141  LOGSYSERROR("Cannot create Status Bar timer: timer_create()");
142  }
143 
144  // unblock signal
145  if( sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1 )
146  {
147  LOGSYSERROR("Cannot unblock Status Bar signal: sigprocmask()");
148  }
149 }
150 
151 /*!
152  * \brief Start the Status Bar timer.
153  *
154  * \param uMSec Timeout in milliseconds.
155  */
156 static void SBTimerStart(uint_t uMSec)
157 {
158  struct itimerspec its;
159 
160  if( SBTimerId != NULL )
161  {
162  // first timeout
163  its.it_value.tv_sec = uMSec / 1000;
164  its.it_value.tv_nsec = (uMSec % 1000) * 1000000;
165 
166  // no repeat interval timer
167  its.it_interval.tv_sec = 0; //its.it_value.tv_sec;
168  its.it_interval.tv_nsec = 0; //its.it_value.tv_nsec;
169 
170  if( timer_settime(SBTimerId, 0, &its, NULL) == -1 )
171  {
172  LOGSYSERROR("Cannot set Status Bar timer: timer_settime()");
173  }
174  }
175 }
176 
177 /*!
178  * \brief Stop the Status Bar timer.
179  */
180 static void SBTimerStop()
181 {
182  struct itimerspec its;
183 
184  if( SBTimerId != NULL )
185  {
186  // disarm
187  its.it_value.tv_sec = 0;
188  its.it_value.tv_nsec = 0;
189 
190  // no repeat interval timer
191  its.it_interval.tv_sec = 0; //its.it_value.tv_sec;
192  its.it_interval.tv_nsec = 0; //its.it_value.tv_nsec;
193 
194  if( timer_settime(SBTimerId, 0, &its, NULL) == -1 )
195  {
196  LOGSYSERROR("Cannot disarm Status Bar timer: timer_settime()");
197  }
198  }
199 }
200 
201 #else // GTK timeout method
202 
203 guint SBTimerId = 0; ///< statue bar timer
204 
205 /*
206  * \brief Status bar timer timeout handler.
207  *
208  * Hides the status bar.
209  *
210  * \param user_data Application specific data
211  *
212  * \return FALSE
213  */
214 static gboolean SBTimerAlarm(gpointer user_data)
215 {
216  SBTimerId = 0;
217  StatusClear();
218  return FALSE;
219 }
220 
221 /*!
222  * \brief Start the Status Bar timer.
223  *
224  * \param uMSec Timeout in milliseconds.
225  */
226 static void SBTimerStart(uint_t uMSec)
227 {
228  SBTimerId = g_timeout_add(uMSec, SBTimerAlarm, NULL);
229 }
230 
231 /*!
232  * \brief Stop the Status Bar timer.
233  */
234 static void SBTimerStop()
235 {
236  if( SBTimerId > 0 )
237  {
238  g_source_remove(SBTimerId);
239  SBTimerId = 0;
240  }
241 }
242 
243 #endif // IT_TIMER
244 
245 /*!
246  * \brief Capture frame event for status bar.
247  *
248  * \note Cannot seem to get this to work.
249  *
250  * \param window GTK window.
251  * \param event The event (e.g. mouse click)
252  * \param data Application data.
253  */
254 void SBFrameEvent(GtkWindow *window, GdkEvent *event, gpointer data)
255 {
256  char *s = (char *)data;
257  //cerr << "dbg: " << event << ", " << s << endl;
258 }
259 
260 /*!
261  * \brief Window state change event handler.
262  *
263  * \param w Widget where keyboard event occurred.
264  * \param event State change event.
265  * \param user_data Supplied user data.
266  *
267  * \return Returns FALSE.
268  */
269 gboolean SBOnWindowState(GtkWidget *w,
270  GdkEventKey *event,
271  gpointer *user_data)
272 {
273  //cerr << "dbg: " << event << endl;
274 }
275 
276 /*!
277  * \brief Create status bar.
278  *
279  * \param pWin Application window.
280  */
281 static void CreateStatusBar(rnrWindow *pWin)
282 {
283  static int h_status = 20; // status window height
284 
285  GtkWindow *wWindow; // gtk window
286  GdkColor color; // background color
287  int x_root; // parent screen x position
288  int y_root; // parent screen y position
289  int w_root; // parent width
290  int h_root; // parent height
291 
292  // get parent position and size
293  wWindow = pWin->GetMainWindowWidget();
294  gtk_window_get_position(wWindow, &x_root, &y_root);
295  gtk_window_get_size(wWindow, &w_root, &h_root);
296 
297  // background color
298  gdk_color_parse("#ffffcf", &color);
299 
300  // status bar window
301  SBWidget = gtk_window_new(GTK_WINDOW_POPUP);
302  SBWindow = GTK_WINDOW(SBWidget);
303  SBWinGeom.x = x_root;
304  SBWinGeom.y = y_root + h_root - h_status;
305  SBWinGeom.width = w_root;
306  SBWinGeom.height = h_status;
307 
308  gtk_window_set_keep_above(SBWindow, true);
309  gtk_window_resize(SBWindow, SBWinGeom.width, SBWinGeom.height);
310  gtk_window_move(SBWindow, SBWinGeom.x, SBWinGeom.y);
311  //gtk_window_set_resizable(SBWindow, false); // cannot use
312  gtk_window_set_decorated(SBWindow, false);
313  gtk_widget_modify_bg(SBWidget, GTK_STATE_NORMAL, &color);
314  gtk_widget_modify_base(SBWidget, GTK_STATE_NORMAL, &color);
315 
316  // status bar label widget
317  SBLabelWidget = gtk_label_new(NULL);
318  gtk_container_add(GTK_CONTAINER(SBWindow), SBLabelWidget);
319 
320  //g_signal_connect(G_OBJECT(SBLabelWidget), "frame-event",
321  // G_CALLBACK(SBFrameEvent), (void *)"frame-event");
322 
323  gtk_signal_connect(GTK_OBJECT(SBWidget), "window-state-event",
324  GTK_SIGNAL_FUNC(SBOnWindowState), NULL);
325 
326  gtk_widget_add_events(SBWidget, GDK_EXPOSURE_MASK |
327  GDK_BUTTON_RELEASE_MASK |
328  GDK_BUTTON_PRESS_MASK |
329  GDK_POINTER_MOTION_MASK);
330 }
331 
332 
333 // ----------------------------------------------------------------------------
334 // Public Interface
335 // ----------------------------------------------------------------------------
336 
337 /*!
338  * \brief Error dialog box.
339  *
340  * \param sWinName Application window name (and id).
341  * \param sMsg Dialog message.
342  */
343 void rnrWin::MsgBox(const char *sWinName, const char *sMsg)
344 {
345  GtkWidget *widget;
346  GtkWindow *window;
347  GtkWidget *wDialog;
348  GtkStyle style;
349  GdkColor color;
350 
351  gdk_color_parse("#ffffcf", &color);
352 
353  widget = (GtkWidget *)cvGetWindowHandle(sWinName);
354  window = GTK_WINDOW(gtk_widget_get_toplevel(widget));
355 
356  wDialog = gtk_message_dialog_new(
357  window,
358  GTK_DIALOG_DESTROY_WITH_PARENT,
359  GTK_MESSAGE_ERROR,
360  GTK_BUTTONS_OK,
361  "%s", sMsg);
362 
363  gtk_widget_modify_bg(wDialog, GTK_STATE_NORMAL, &color);
364  gtk_widget_modify_base(wDialog, GTK_STATE_NORMAL, &color);
365 
366  gtk_dialog_run( GTK_DIALOG(wDialog) );
367  gtk_widget_destroy(wDialog);
368 }
369 
370 /*!
371  * \brief Show status message.
372  *
373  * \param pWin Application window.
374  * \param uMSec If zero, the message requires a mouse click to clear.
375  * Others, the status auto-clears in the give milliseconds.
376  * \param sFmt Format string.
377  * \param ... Variable arguments to format string.
378  */
379 void rnrWin::StatusShow(rnrWindow *pWin,
380  uint_t uMSec,
381  const char *sFmt,
382  ...)
383 {
384  static int h_status = 20; // status window height
385 
386  char buf[256]; // working buffer
387  va_list ap; // variable argument pointer
388 
389  // create status bar
390  if( SBWidget == NULL )
391  {
392  CreateStatusBar(pWin);
393  }
394 
395 #ifdef IT_TIMER
396  // create status bar timer
397  if( SBTimerId == NULL )
398  {
399  SBTimerCreate();
400  }
401 #endif // IT_TIMER
402 
403  // stop any timer
404  SBTimerStop();
405 
406  // format message
407  va_start(ap, sFmt);
408  vsnprintf(buf, sizeof(buf), sFmt, ap);
409  va_end(ap);
410  buf[sizeof(buf)-1] = 0;
411 
412  //cerr << "dbg: " << uMSec << " " << buf << endl;
413 
414  // set text
415  gtk_label_set_text(GTK_LABEL(SBLabelWidget), buf);
416 
417  // reshow window
418  gtk_window_move(SBWindow, SBWinGeom.x, SBWinGeom.y);
419  gtk_window_resize(SBWindow, SBWinGeom.width, SBWinGeom.height);
420  gtk_widget_show(SBLabelWidget);
421  gtk_widget_show(SBWidget);
422  gtk_widget_queue_draw( GTK_WIDGET(SBLabelWidget) );
423  SBIsVisible = true;
424  pWin->WaitKey(100); // give time to draw
425 
426  if( uMSec > 0 )
427  {
428  SBTimerStart(uMSec);
429  }
430 }
431 
432 /*!
433  * \brief Clear status message.
434  */
435 void rnrWin::StatusClear()
436 {
437  SBTimerStop();
438 
439  if( (SBWidget != NULL) && SBIsVisible )
440  {
441  gtk_widget_hide(SBWidget);
442  SBIsVisible = false;
443  }
444 }
static void SBTimerStop()
Stop the Status Bar timer.
Definition: WinGtkMsg.cxx:234
static CvRect SBWinGeom
status bar window geometry
Definition: WinGtkMsg.cxx:96
RoadNarrows Robotics Win abstract base class interface.
guint SBTimerId
statue bar timer
Definition: WinGtkMsg.cxx:203
static GtkWidget * SBLabelWidget
status bar label gtk widget
Definition: WinGtkMsg.cxx:95
static GtkWidget * SBWidget
status bar gtk widget
Definition: WinGtkMsg.cxx:92
static bool SBIsVisible
status bar is [not] visible
Definition: WinGtkMsg.cxx:93
static void SBTimerStart(uint_t uMSec)
Start the Status Bar timer.
Definition: WinGtkMsg.cxx:226
gboolean SBOnWindowState(GtkWidget *w, GdkEventKey *event, gpointer *user_data)
Window state change event handler.
Definition: WinGtkMsg.cxx:269
static GtkWindow * SBWindow
status bar gtk window
Definition: WinGtkMsg.cxx:94
static void CreateStatusBar(rnrWindow *pWin)
Create status bar.
Definition: WinGtkMsg.cxx:281
void SBFrameEvent(GtkWindow *window, GdkEvent *event, gpointer data)
Capture frame event for status bar.
Definition: WinGtkMsg.cxx:254