window.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,007 行 · 第 1/5 页
CPP
2,007 行
/////////////////////////////////////////////////////////////////////////////
// Name: gtk/window.cpp
// Purpose:
// Author: Robert Roebling
// Id: $Id: window.cpp,v 1.548.2.14 2006/03/30 10:36:22 RR Exp $
// Copyright: (c) 1998 Robert Roebling, Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "window.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __VMS
#define XWarpPointer XWARPPOINTER
#endif
#include "wx/window.h"
#include "wx/dcclient.h"
#include "wx/frame.h"
#include "wx/app.h"
#include "wx/layout.h"
#include "wx/utils.h"
#include "wx/dialog.h"
#include "wx/msgdlg.h"
#include "wx/module.h"
#include "wx/combobox.h"
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#endif
#if wxUSE_TOOLTIPS
#include "wx/tooltip.h"
#endif
#if wxUSE_CARET
#include "wx/caret.h"
#endif // wxUSE_CARET
#if wxUSE_TEXTCTRL
#include "wx/textctrl.h"
#endif
#include "wx/menu.h"
#include "wx/statusbr.h"
#include "wx/intl.h"
#include "wx/settings.h"
#include "wx/log.h"
#include "wx/fontutil.h"
#ifdef __WXDEBUG__
#include "wx/thread.h"
#endif
#include "wx/math.h"
#include <ctype.h>
#include "wx/gtk/private.h"
#include <gdk/gdkprivate.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <gtk/gtkprivate.h>
#include "wx/gtk/win_gtk.h"
#ifdef __WXGTK20__
#include <pango/pangox.h>
#endif
#ifdef __WXGTK20__
#ifdef HAVE_XIM
#undef HAVE_XIM
#endif
#endif
#ifdef __WXGTK20__
extern GtkContainerClass *pizza_parent_class;
#endif
//-----------------------------------------------------------------------------
// documentation on internals
//-----------------------------------------------------------------------------
/*
I have been asked several times about writing some documentation about
the GTK port of wxWidgets, especially its internal structures. Obviously,
you cannot understand wxGTK without knowing a little about the GTK, but
some more information about what the wxWindow, which is the base class
for all other window classes, does seems required as well.
I)
What does wxWindow do? It contains the common interface for the following
jobs of its descendants:
1) Define the rudimentary behaviour common to all window classes, such as
resizing, intercepting user input (so as to make it possible to use these
events for special purposes in a derived class), window names etc.
2) Provide the possibility to contain and manage children, if the derived
class is allowed to contain children, which holds true for those window
classes which do not display a native GTK widget. To name them, these
classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
work classes are a special case and are handled a bit differently from
the rest. The same holds true for the wxNotebook class.
3) Provide the possibility to draw into a client area of a window. This,
too, only holds true for classes that do not display a native GTK widget
as above.
4) Provide the entire mechanism for scrolling widgets. This actual inter-
face for this is usually in wxScrolledWindow, but the GTK implementation
is in this class.
5) A multitude of helper or extra methods for special purposes, such as
Drag'n'Drop, managing validators etc.
6) Display a border (sunken, raised, simple or none).
Normally one might expect, that one wxWidgets window would always correspond
to one GTK widget. Under GTK, there is no such allround widget that has all
the functionality. Moreover, the GTK defines a client area as a different
widget from the actual widget you are handling. Last but not least some
special classes (e.g. wxFrame) handle different categories of widgets and
still have the possibility to draw something in the client area.
It was therefore required to write a special purpose GTK widget, that would
represent a client area in the sense of wxWidgets capable to do the jobs
2), 3) and 4). I have written this class and it resides in win_gtk.c of
this directory.
All windows must have a widget, with which they interact with other under-
lying GTK widgets. It is this widget, e.g. that has to be resized etc and
thw wxWindow class has a member variable called m_widget which holds a
pointer to this widget. When the window class represents a GTK native widget,
this is (in most cases) the only GTK widget the class manages. E.g. the
wxStaticText class handles only a GtkLabel widget a pointer to which you
can find in m_widget (defined in wxWindow)
When the class has a client area for drawing into and for containing children
it has to handle the client area widget (of the type GtkPizza, defined in
win_gtk.c), but there could be any number of widgets, handled by a class
The common rule for all windows is only, that the widget that interacts with
the rest of GTK must be referenced in m_widget and all other widgets must be
children of this widget on the GTK level. The top-most widget, which also
represents the client area, must be in the m_wxwindow field and must be of
the type GtkPizza.
As I said, the window classes that display a GTK native widget only have
one widget, so in the case of e.g. the wxButton class m_widget holds a
pointer to a GtkButton widget. But windows with client areas (for drawing
and children) have a m_widget field that is a pointer to a GtkScrolled-
Window and a m_wxwindow field that is pointer to a GtkPizza and this
one is (in the GTK sense) a child of the GtkScrolledWindow.
If the m_wxwindow field is set, then all input to this widget is inter-
cepted and sent to the wxWidgets class. If not, all input to the widget
that gets pointed to by m_widget gets intercepted and sent to the class.
II)
The design of scrolling in wxWidgets is markedly different from that offered
by the GTK itself and therefore we cannot simply take it as it is. In GTK,
clicking on a scrollbar belonging to scrolled window will inevitably move
the window. In wxWidgets, the scrollbar will only emit an event, send this
to (normally) a wxScrolledWindow and that class will call ScrollWindow()
which actually moves the window and its subchildren. Note that GtkPizza
memorizes how much it has been scrolled but that wxWidgets forgets this
so that the two coordinates systems have to be kept in synch. This is done
in various places using the pizza->xoffset and pizza->yoffset values.
III)
Singularily the most broken code in GTK is the code that is supposes to
inform subwindows (child windows) about new positions. Very often, duplicate
events are sent without changes in size or position, equally often no
events are sent at all (All this is due to a bug in the GtkContainer code
which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
GTK's own system and it simply waits for size events for toplevel windows
and then iterates down the respective size events to all window. This has
the disadvantage, that windows might get size events before the GTK widget
actually has the reported size. This doesn't normally pose any problem, but
the OpenGl drawing routines rely on correct behaviour. Therefore, I have
added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
window that is used for OpenGl output really has that size (as reported by
GTK).
IV)
If someone at some point of time feels the immense desire to have a look at,
change or attempt to optimse the Refresh() logic, this person will need an
intimate understanding of what a "draw" and what an "expose" events are and
what there are used for, in particular when used in connection with GTK's
own windowless widgets. Beware.
V)
Cursors, too, have been a constant source of pleasure. The main difficulty
is that a GdkWindow inherits a cursor if the programmer sets a new cursor
for the parent. To prevent this from doing too much harm, I use idle time
to set the cursor over and over again, starting from the toplevel windows
and ending with the youngest generation (speaking of parent and child windows).
Also don't forget that cursors (like much else) are connected to GdkWindows,
not GtkWidgets and that the "window" field of a GtkWidget might very well
point to the GdkWindow of the parent widget (-> "window less widget") and
that the two obviously have very different meanings.
*/
//-----------------------------------------------------------------------------
// data
//-----------------------------------------------------------------------------
extern wxList wxPendingDelete;
extern bool g_blockEventsOnDrag;
extern bool g_blockEventsOnScroll;
extern wxCursor g_globalCursor;
static GdkGC *g_eraseGC = NULL;
// mouse capture state: the window which has it and if the mouse is currently
// inside it
static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
static bool g_captureWindowHasMouse = false;
wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
// the last window which had the focus - this is normally never NULL (except
// if we never had focus at all) as even when g_focusWindow is NULL it still
// keeps its previous value
wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
// If a window get the focus set but has not been realized
// yet, defer setting the focus to idle time.
wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
// hack: we need something to pass to gtk_menu_popup, so we store the time of
// the last click here
static guint32 gs_timeLastClick = 0;
extern bool g_mainThreadLocked;
//-----------------------------------------------------------------------------
// debug
//-----------------------------------------------------------------------------
#ifdef __WXDEBUG__
#if wxUSE_THREADS
# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
#else
# define DEBUG_MAIN_THREAD
#endif
#else
#define DEBUG_MAIN_THREAD
#endif // Debug
// the trace mask used for the focus debugging messages
#define TRACE_FOCUS _T("focus")
//-----------------------------------------------------------------------------
// missing gdk functions
//-----------------------------------------------------------------------------
void
gdk_window_warp_pointer (GdkWindow *window,
gint x,
gint y)
{
#ifndef __WXGTK20__
GdkWindowPrivate *priv;
#endif
if (!window)
window = GDK_ROOT_PARENT();
#ifdef __WXGTK20__
if (!GDK_WINDOW_DESTROYED(window))
{
XWarpPointer (GDK_WINDOW_XDISPLAY(window),
None, /* not source window -> move from anywhere */
GDK_WINDOW_XID(window), /* dest window */
0, 0, 0, 0, /* not source window -> move from anywhere */
x, y );
}
#else
priv = (GdkWindowPrivate*) window;
if (!priv->destroyed)
{
XWarpPointer (priv->xdisplay,
None, /* not source window -> move from anywhere */
priv->xwindow, /* dest window */
0, 0, 0, 0, /* not source window -> move from anywhere */
x, y );
}
#endif
}
//-----------------------------------------------------------------------------
// idle system
//-----------------------------------------------------------------------------
extern void wxapp_install_idle_handler();
extern bool g_isIdle;
//-----------------------------------------------------------------------------
// local code (see below)
//-----------------------------------------------------------------------------
// returns the child of win which currently has focus or NULL if not found
//
// Note: can't be static, needed by textctrl.cpp.
wxWindow *wxFindFocusedChild(wxWindowGTK *win)
{
wxWindow *winFocus = wxWindowGTK::FindFocus();
if ( !winFocus )
return (wxWindow *)NULL;
if ( winFocus == win )
return (wxWindow *)win;
for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow *child = wxFindFocusedChild(node->GetData());
if ( child )
return child;
}
return (wxWindow *)NULL;
}
static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
{
// wxUniversal widgets draw the borders and scrollbars themselves
#ifndef __WXUNIVERSAL__
if (!win->m_hasVMT)
return;
int dw = 0;
int dh = 0;
if (win->m_hasScrolling)
{
GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
GtkRequisition vscroll_req;
vscroll_req.width = 2;
vscroll_req.height = 2;
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
(scroll_window->vscrollbar, &vscroll_req );
GtkRequisition hscroll_req;
hscroll_req.width = 2;
hscroll_req.height = 2;
(* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
(scroll_window->hscrollbar, &hscroll_req );
GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
if (scroll_window->vscrollbar_visible)
{
dw += vscroll_req.width;
dw += scroll_class->scrollbar_spacing;
}
if (scroll_window->hscrollbar_visible)
{
dh += hscroll_req.height;
dh += scroll_class->scrollbar_spacing;
}
}
int dx = 0;
int dy = 0;
if (GTK_WIDGET_NO_WINDOW (widget))
{
dx += widget->allocation.x;
dy += widget->allocation.y;
}
if (win->HasFlag(wxRAISED_BORDER))
{
gtk_draw_shadow( widget->style,
widget->window,
GTK_STATE_NORMAL,
GTK_SHADOW_OUT,
dx, dy,
widget->allocation.width-dw, widget->allocation.height-dh );
return;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?