From dca92ddfbff8fc0a858ada23c4ece06cdbe229c8 Mon Sep 17 00:00:00 2001 From: Mart Raudsepp Date: Thu, 28 Jul 2005 23:32:42 +0000 Subject: [PATCH] wxGTK: Implemented wxTLW::RequestUserAttention() git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34973 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/tlw.tex | 4 +- include/wx/gtk/toplevel.h | 2 + include/wx/gtk1/toplevel.h | 2 + src/gtk/toplevel.cpp | 123 +++++++++++++++++++++++++++++++++++++ src/gtk1/toplevel.cpp | 123 +++++++++++++++++++++++++++++++++++++ 6 files changed, 253 insertions(+), 2 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index f69f4b42f3..91201f08e4 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -36,6 +36,7 @@ wxWinCE: wxGTK: - ShowFullScreen() shows the window if it was still hidden (rpedroso) +- Implemented wxTopLevelWindow::RequestUserAttention() (Mart Raudsepp) wxOS2 diff --git a/docs/latex/wx/tlw.tex b/docs/latex/wx/tlw.tex index 6cada953fe..812eebd334 100644 --- a/docs/latex/wx/tlw.tex +++ b/docs/latex/wx/tlw.tex @@ -148,8 +148,8 @@ action. When in doubt, use the default value. Note that this function should normally be only used when the application is not already in foreground. -This function is currently only implemented for Win32 where it flashes the -window icon in the taskbar. +This function is currently implemented for Win32 where it flashes the +window icon in the taskbar, and for wxGTK with task bars supporting it. \membersection{wxTopLevelWindow::SetIcon}\label{wxtoplevelwindowseticon} diff --git a/include/wx/gtk/toplevel.h b/include/wx/gtk/toplevel.h index d4464c2ec9..a36b2846da 100644 --- a/include/wx/gtk/toplevel.h +++ b/include/wx/gtk/toplevel.h @@ -62,6 +62,8 @@ public: virtual bool SetShape(const wxRegion& region); + virtual void RequestUserAttention(int flags = wxUSER_ATTENTION_INFO); + virtual bool Show(bool show = TRUE); virtual void Raise(); diff --git a/include/wx/gtk1/toplevel.h b/include/wx/gtk1/toplevel.h index d4464c2ec9..a36b2846da 100644 --- a/include/wx/gtk1/toplevel.h +++ b/include/wx/gtk1/toplevel.h @@ -62,6 +62,8 @@ public: virtual bool SetShape(const wxRegion& region); + virtual void RequestUserAttention(int flags = wxUSER_ATTENTION_INFO); + virtual bool Show(bool show = TRUE); virtual void Raise(); diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index dc78d711d0..6dc85efbf4 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -79,6 +79,47 @@ static wxTopLevelWindowGTK *g_lastActiveFrame = (wxTopLevelWindowGTK*) NULL; // send any activate events at all static int g_sendActivateEvent = -1; +//----------------------------------------------------------------------------- +// RequestUserAttention related functions +//----------------------------------------------------------------------------- + +extern "C" { +static void wxgtk_window_set_urgency_hint (GtkWindow *win, + gboolean setting) +{ + wxASSERT_MSG( GTK_WIDGET_REALIZED(win), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") ); + GdkWindow *window = GTK_WIDGET(win)->window; + XWMHints *wm_hints; + + wm_hints = XGetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window)); + + if (!wm_hints) + wm_hints = XAllocWMHints(); + + if (setting) + wm_hints->flags |= XUrgencyHint; + else + wm_hints->flags &= ~XUrgencyHint; + + XSetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window), wm_hints); + XFree(wm_hints); +} + +static gint gtk_frame_urgency_timer_callback( GtkWidget *win ) +{ +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( win ), FALSE); + else +#endif + wxgtk_window_set_urgency_hint(GTK_WINDOW( win ), FALSE); + + //BCI: argument from GtkWidget* to wxTopLevelWindowGTK* && win->m_urgency_hint = -2; + gtk_object_set_data(GTK_OBJECT(win), "m_urgency_hint", GINT_TO_POINTER(-2)); + return FALSE; +} +} + //----------------------------------------------------------------------------- // "focus_in_event" //----------------------------------------------------------------------------- @@ -110,6 +151,31 @@ static gint gtk_frame_focus_in_callback( GtkWidget *widget, // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() ); + // MR: wxRequestUserAttention related block + //BCI: switch(win->m_urgency_hint) + switch( GPOINTER_TO_INT(gtk_object_get_data( GTK_OBJECT(widget), "m_urgency_hint") ) ) + { + default: + //BCI: + gtk_timeout_remove( GPOINTER_TO_INT(gtk_object_get_data( GTK_OBJECT(widget), "m_urgency_hint") ) ); + // no break, fallthrough to remove hint too + case -1: +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE); + else +#endif + { + wxgtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE); + } + + //BCI: win->m_urgency_hint = -2; + gtk_object_set_data( GTK_OBJECT(widget), "m_urgency_hint", GINT_TO_POINTER(-2) ); + break; + + case -2: break; + } + wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame); wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId()); event.SetEventObject(g_activeFrame); @@ -420,6 +486,13 @@ void wxTopLevelWindowGTK::Init() m_themeEnabled = true; m_gdkDecor = m_gdkFunc = 0; m_grabbed = false; + + //BCI: header wx/gtk/toplevel.h: + // private gtk_timeout_add result for mimicing wxUSER_ATTENTION_INFO and + // wxUSER_ATTENTION_ERROR difference, -2 for no hint, -1 for ERROR hint, rest for GtkTimeout handle. + // int m_urgency_hint; + + //BCI: m_urgency_hint = -2; } bool wxTopLevelWindowGTK::Create( wxWindow *parent, @@ -493,6 +566,9 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, } } + // BCI: + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-2) ); + wxWindow *topParent = wxGetTopLevelParent(m_parent); if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) && (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) || @@ -1266,3 +1342,50 @@ bool wxTopLevelWindowGTK::IsActive() { return (this == (wxTopLevelWindowGTK*)g_activeFrame); } + +void wxTopLevelWindowGTK::RequestUserAttention(int flags) +{ + bool new_hint_value = false; + + // FIXME: This is a workaround to focus handling problem + // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't + // yet been processed, and the internal focus system is not up to date yet. + // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR + ::wxYieldIfNeeded(); + + /*BCI: + if(m_urgency_hint >= 0) + gtk_timeout_remove(m_urgency_hint); + */ + int urgency_hint = GPOINTER_TO_INT( gtk_object_get_data( GTK_OBJECT(m_widget), "m_urgency_hint") ); + if(urgency_hint >= 0) + gtk_timeout_remove(urgency_hint); + //BCI: END + + //BCI: m_urgency_hint = -2; + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-2)); + + if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() ) + { + new_hint_value = true; + + if (flags & wxUSER_ATTENTION_INFO) + { + //BCI: m_urgency_hint = gtk_timeout_add(5000, (GtkFunction)gtk_frame_urgency_timer_callback, this); + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", + GINT_TO_POINTER( gtk_timeout_add(5000, + (GtkFunction)gtk_frame_urgency_timer_callback, + m_widget) ) ); + } else { + //BCI: m_urgency_hint = -1; + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-1) ); + } + } + +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value); + else +#endif + wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value); +} diff --git a/src/gtk1/toplevel.cpp b/src/gtk1/toplevel.cpp index dc78d711d0..6dc85efbf4 100644 --- a/src/gtk1/toplevel.cpp +++ b/src/gtk1/toplevel.cpp @@ -79,6 +79,47 @@ static wxTopLevelWindowGTK *g_lastActiveFrame = (wxTopLevelWindowGTK*) NULL; // send any activate events at all static int g_sendActivateEvent = -1; +//----------------------------------------------------------------------------- +// RequestUserAttention related functions +//----------------------------------------------------------------------------- + +extern "C" { +static void wxgtk_window_set_urgency_hint (GtkWindow *win, + gboolean setting) +{ + wxASSERT_MSG( GTK_WIDGET_REALIZED(win), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") ); + GdkWindow *window = GTK_WIDGET(win)->window; + XWMHints *wm_hints; + + wm_hints = XGetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window)); + + if (!wm_hints) + wm_hints = XAllocWMHints(); + + if (setting) + wm_hints->flags |= XUrgencyHint; + else + wm_hints->flags &= ~XUrgencyHint; + + XSetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window), wm_hints); + XFree(wm_hints); +} + +static gint gtk_frame_urgency_timer_callback( GtkWidget *win ) +{ +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( win ), FALSE); + else +#endif + wxgtk_window_set_urgency_hint(GTK_WINDOW( win ), FALSE); + + //BCI: argument from GtkWidget* to wxTopLevelWindowGTK* && win->m_urgency_hint = -2; + gtk_object_set_data(GTK_OBJECT(win), "m_urgency_hint", GINT_TO_POINTER(-2)); + return FALSE; +} +} + //----------------------------------------------------------------------------- // "focus_in_event" //----------------------------------------------------------------------------- @@ -110,6 +151,31 @@ static gint gtk_frame_focus_in_callback( GtkWidget *widget, // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() ); + // MR: wxRequestUserAttention related block + //BCI: switch(win->m_urgency_hint) + switch( GPOINTER_TO_INT(gtk_object_get_data( GTK_OBJECT(widget), "m_urgency_hint") ) ) + { + default: + //BCI: + gtk_timeout_remove( GPOINTER_TO_INT(gtk_object_get_data( GTK_OBJECT(widget), "m_urgency_hint") ) ); + // no break, fallthrough to remove hint too + case -1: +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE); + else +#endif + { + wxgtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE); + } + + //BCI: win->m_urgency_hint = -2; + gtk_object_set_data( GTK_OBJECT(widget), "m_urgency_hint", GINT_TO_POINTER(-2) ); + break; + + case -2: break; + } + wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame); wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId()); event.SetEventObject(g_activeFrame); @@ -420,6 +486,13 @@ void wxTopLevelWindowGTK::Init() m_themeEnabled = true; m_gdkDecor = m_gdkFunc = 0; m_grabbed = false; + + //BCI: header wx/gtk/toplevel.h: + // private gtk_timeout_add result for mimicing wxUSER_ATTENTION_INFO and + // wxUSER_ATTENTION_ERROR difference, -2 for no hint, -1 for ERROR hint, rest for GtkTimeout handle. + // int m_urgency_hint; + + //BCI: m_urgency_hint = -2; } bool wxTopLevelWindowGTK::Create( wxWindow *parent, @@ -493,6 +566,9 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, } } + // BCI: + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-2) ); + wxWindow *topParent = wxGetTopLevelParent(m_parent); if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) && (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) || @@ -1266,3 +1342,50 @@ bool wxTopLevelWindowGTK::IsActive() { return (this == (wxTopLevelWindowGTK*)g_activeFrame); } + +void wxTopLevelWindowGTK::RequestUserAttention(int flags) +{ + bool new_hint_value = false; + + // FIXME: This is a workaround to focus handling problem + // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't + // yet been processed, and the internal focus system is not up to date yet. + // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR + ::wxYieldIfNeeded(); + + /*BCI: + if(m_urgency_hint >= 0) + gtk_timeout_remove(m_urgency_hint); + */ + int urgency_hint = GPOINTER_TO_INT( gtk_object_get_data( GTK_OBJECT(m_widget), "m_urgency_hint") ); + if(urgency_hint >= 0) + gtk_timeout_remove(urgency_hint); + //BCI: END + + //BCI: m_urgency_hint = -2; + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-2)); + + if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() ) + { + new_hint_value = true; + + if (flags & wxUSER_ATTENTION_INFO) + { + //BCI: m_urgency_hint = gtk_timeout_add(5000, (GtkFunction)gtk_frame_urgency_timer_callback, this); + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", + GINT_TO_POINTER( gtk_timeout_add(5000, + (GtkFunction)gtk_frame_urgency_timer_callback, + m_widget) ) ); + } else { + //BCI: m_urgency_hint = -1; + gtk_object_set_data( GTK_OBJECT(m_widget), "m_urgency_hint", GINT_TO_POINTER(-1) ); + } + } + +#if __WXGTK20__ && GTK_CHECK_VERSION(2,7,0) + if(!gtk_check_version(2,7,0)) + gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value); + else +#endif + wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value); +} -- 2.45.2