]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/window.cpp
normalized handling of Ctrl-x key presses and documented it clearly
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #ifdef __VMS
16 #define XWarpPointer XWARPPOINTER
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
22 #include "wx/frame.h"
23 #include "wx/app.h"
24 #include "wx/layout.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #if wxUSE_TOOLTIPS
34 #include "wx/tooltip.h"
35 #endif
36
37 #if wxUSE_CARET
38 #include "wx/caret.h"
39 #endif // wxUSE_CARET
40
41 #if wxUSE_TEXTCTRL
42 #include "wx/textctrl.h"
43 #endif
44
45 #include "wx/menu.h"
46 #include "wx/statusbr.h"
47 #include "wx/intl.h"
48 #include "wx/settings.h"
49 #include "wx/log.h"
50
51 #ifdef __WXDEBUG__
52 #include "wx/thread.h"
53 #endif
54
55 #include <math.h>
56
57 #include <gdk/gdk.h>
58 #include <gtk/gtk.h>
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
61 #include <gdk/gdkx.h>
62
63 #include <gtk/gtk.h>
64 #include <gtk/gtkprivate.h>
65
66 #include "wx/gtk/win_gtk.h"
67
68 //-----------------------------------------------------------------------------
69 // documentation on internals
70 //-----------------------------------------------------------------------------
71
72 /*
73 I have been asked several times about writing some documentation about
74 the GTK port of wxWindows, especially its internal structures. Obviously,
75 you cannot understand wxGTK without knowing a little about the GTK, but
76 some more information about what the wxWindow, which is the base class
77 for all other window classes, does seems required as well.
78
79 I)
80
81 What does wxWindow do? It contains the common interface for the following
82 jobs of its descendants:
83
84 1) Define the rudimentary behaviour common to all window classes, such as
85 resizing, intercepting user input (so as to make it possible to use these
86 events for special purposes in a derived class), window names etc.
87
88 2) Provide the possibility to contain and manage children, if the derived
89 class is allowed to contain children, which holds true for those window
90 classes which do not display a native GTK widget. To name them, these
91 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
92 work classes are a special case and are handled a bit differently from
93 the rest. The same holds true for the wxNotebook class.
94
95 3) Provide the possibility to draw into a client area of a window. This,
96 too, only holds true for classes that do not display a native GTK widget
97 as above.
98
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
101 is in this class.
102
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
105
106 6) Display a border (sunken, raised, simple or none).
107
108 Normally one might expect, that one wxWindows window would always correspond
109 to one GTK widget. Under GTK, there is no such allround widget that has all
110 the functionality. Moreover, the GTK defines a client area as a different
111 widget from the actual widget you are handling. Last but not least some
112 special classes (e.g. wxFrame) handle different categories of widgets and
113 still have the possibility to draw something in the client area.
114 It was therefore required to write a special purpose GTK widget, that would
115 represent a client area in the sense of wxWindows capable to do the jobs
116 2), 3) and 4). I have written this class and it resides in win_gtk.c of
117 this directory.
118
119 All windows must have a widget, with which they interact with other under-
120 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
121 thw wxWindow class has a member variable called m_widget which holds a
122 pointer to this widget. When the window class represents a GTK native widget,
123 this is (in most cases) the only GTK widget the class manages. E.g. the
124 wxStatitText class handles only a GtkLabel widget a pointer to which you
125 can find in m_widget (defined in wxWindow)
126
127 When the class has a client area for drawing into and for containing children
128 it has to handle the client area widget (of the type GtkPizza, defined in
129 win_gtk.c), but there could be any number of widgets, handled by a class
130 The common rule for all windows is only, that the widget that interacts with
131 the rest of GTK must be referenced in m_widget and all other widgets must be
132 children of this widget on the GTK level. The top-most widget, which also
133 represents the client area, must be in the m_wxwindow field and must be of
134 the type GtkPizza.
135
136 As I said, the window classes that display a GTK native widget only have
137 one widget, so in the case of e.g. the wxButton class m_widget holds a
138 pointer to a GtkButton widget. But windows with client areas (for drawing
139 and children) have a m_widget field that is a pointer to a GtkScrolled-
140 Window and a m_wxwindow field that is pointer to a GtkPizza and this
141 one is (in the GTK sense) a child of the GtkScrolledWindow.
142
143 If the m_wxwindow field is set, then all input to this widget is inter-
144 cepted and sent to the wxWindows class. If not, all input to the widget
145 that gets pointed to by m_widget gets intercepted and sent to the class.
146
147 II)
148
149 The design of scrolling in wxWindows is markedly different from that offered
150 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151 clicking on a scrollbar belonging to scrolled window will inevitably move
152 the window. In wxWindows, the scrollbar will only emit an event, send this
153 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
154 which actually moves the window and its subchildren. Note that GtkPizza
155 memorizes how much it has been scrolled but that wxWindows forgets this
156 so that the two coordinates systems have to be kept in synch. This is done
157 in various places using the pizza->xoffset and pizza->yoffset values.
158
159 III)
160
161 Singularily the most broken code in GTK is the code that is supposes to
162 inform subwindows (child windows) about new positions. Very often, duplicate
163 events are sent without changes in size or position, equally often no
164 events are sent at all (All this is due to a bug in the GtkContainer code
165 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166 GTK's own system and it simply waits for size events for toplevel windows
167 and then iterates down the respective size events to all window. This has
168 the disadvantage, that windows might get size events before the GTK widget
169 actually has the reported size. This doesn't normally pose any problem, but
170 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
171 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173 window that is used for OpenGl output really has that size (as reported by
174 GTK).
175
176 IV)
177
178 If someone at some point of time feels the immense desire to have a look at,
179 change or attempt to optimse the Refresh() logic, this person will need an
180 intimate understanding of what a "draw" and what an "expose" events are and
181 what there are used for, in particular when used in connection with GTK's
182 own windowless widgets. Beware.
183
184 V)
185
186 Cursors, too, have been a constant source of pleasure. The main difficulty
187 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188 for the parent. To prevent this from doing too much harm, I use idle time
189 to set the cursor over and over again, starting from the toplevel windows
190 and ending with the youngest generation (speaking of parent and child windows).
191 Also don't forget that cursors (like much else) are connected to GdkWindows,
192 not GtkWidgets and that the "window" field of a GtkWidget might very well
193 point to the GdkWindow of the parent widget (-> "window less widget") and
194 that the two obviously have very different meanings.
195
196 */
197
198 //-----------------------------------------------------------------------------
199 // data
200 //-----------------------------------------------------------------------------
201
202 extern wxList wxPendingDelete;
203 extern bool g_blockEventsOnDrag;
204 extern bool g_blockEventsOnScroll;
205 extern wxCursor g_globalCursor;
206
207 // mouse capture state: the window which has it and if the mouse is currently
208 // inside it
209 static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
210 static bool g_captureWindowHasMouse = FALSE;
211
212 /* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
213
214 // the last window which had the focus - this is normally never NULL (except
215 // if we never had focus at all) as even when g_focusWindow is NULL it still
216 // keeps its previous value
217 static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
218
219 // the frame that is currently active (i.e. its child has focus). It is
220 // used to generate wxActivateEvents
221 static wxWindowGTK *g_activeFrame = (wxWindowGTK *)NULL;
222 static bool g_activeFrameLostFocus = FALSE;
223
224 // if we detect that the app has got/lost the focus, we set this variable to
225 // either TRUE or FALSE and an activate event will be sent during the next
226 // OnIdle() call and it is reset to -1: this value means that we shouldn't
227 // send any activate events at all
228 static int g_sendActivateEvent = -1;
229
230 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
231 the last click here */
232 static guint32 gs_timeLastClick = 0;
233
234 extern bool g_mainThreadLocked;
235
236 //-----------------------------------------------------------------------------
237 // debug
238 //-----------------------------------------------------------------------------
239
240 #ifndef __WXGTK20__
241 #define DISABLE_STYLE_IF_BROKEN_THEME 1
242 #endif
243
244 #ifdef __WXDEBUG__
245
246 #if wxUSE_THREADS
247 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
248 #else
249 # define DEBUG_MAIN_THREAD
250 #endif
251
252 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
253 GdkEvent *WXUNUSED(event),
254 const wxChar *WXUNUSED(name) )
255 {
256 /*
257 static bool s_done = FALSE;
258 if ( !s_done )
259 {
260 wxLog::AddTraceMask("focus");
261 s_done = TRUE;
262 }
263 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
264 */
265
266 return FALSE;
267 }
268
269 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
270 {
271 // suppress warnings about gtk_debug_focus_in_callback being unused with
272 // this "if ( 0 )"
273 if ( 0 )
274 {
275 wxString tmp = name;
276 tmp += wxT(" FROM ");
277 tmp += window;
278
279 wxChar *s = new wxChar[tmp.Length()+1];
280
281 wxStrcpy( s, tmp );
282
283 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
284 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
285 }
286 }
287
288 #else
289 #define DEBUG_MAIN_THREAD
290 #endif // Debug
291
292 //-----------------------------------------------------------------------------
293 // missing gdk functions
294 //-----------------------------------------------------------------------------
295
296 void
297 gdk_window_warp_pointer (GdkWindow *window,
298 gint x,
299 gint y)
300 {
301 #ifndef __WXGTK20__
302 GdkWindowPrivate *priv;
303 #endif
304
305 if (!window)
306 window = GDK_ROOT_PARENT();
307
308 #ifdef __WXGTK20__
309 if (!GDK_WINDOW_DESTROYED(window))
310 {
311 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
312 None, /* not source window -> move from anywhere */
313 GDK_WINDOW_XID(window), /* dest window */
314 0, 0, 0, 0, /* not source window -> move from anywhere */
315 x, y );
316 }
317 #else
318 priv = (GdkWindowPrivate*) window;
319
320 if (!priv->destroyed)
321 {
322 XWarpPointer (priv->xdisplay,
323 None, /* not source window -> move from anywhere */
324 priv->xwindow, /* dest window */
325 0, 0, 0, 0, /* not source window -> move from anywhere */
326 x, y );
327 }
328 #endif
329 }
330
331 //-----------------------------------------------------------------------------
332 // idle system
333 //-----------------------------------------------------------------------------
334
335 extern void wxapp_install_idle_handler();
336 extern bool g_isIdle;
337
338 //-----------------------------------------------------------------------------
339 // local code (see below)
340 //-----------------------------------------------------------------------------
341
342 // returns the child of win which currently has focus or NULL if not found
343 //
344 // Note: can't be static, needed by textctrl.cpp.
345 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
346 {
347 wxWindow *winFocus = wxWindowGTK::FindFocus();
348 if ( !winFocus )
349 return (wxWindow *)NULL;
350
351 if ( winFocus == win )
352 return (wxWindow *)win;
353
354 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
355 node;
356 node = node->GetNext() )
357 {
358 wxWindow *child = wxFindFocusedChild(node->GetData());
359 if ( child )
360 return child;
361 }
362
363 return (wxWindow *)NULL;
364 }
365
366 // Returns toplevel grandparent of given window:
367 static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
368 {
369 wxWindowGTK *p = win;
370 while (p && !p->IsTopLevel())
371 p = p->GetParent();
372 return p;
373 }
374
375
376 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
377 {
378 // wxUniversal widgets draw the borders and scrollbars themselves
379 #ifndef __WXUNIVERSAL__
380 if (!win->m_hasVMT)
381 return;
382
383 int dw = 0;
384 int dh = 0;
385
386 if (win->m_hasScrolling)
387 {
388 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
389
390 GtkRequisition vscroll_req;
391 vscroll_req.width = 2;
392 vscroll_req.height = 2;
393 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
394 (scroll_window->vscrollbar, &vscroll_req );
395
396 GtkRequisition hscroll_req;
397 hscroll_req.width = 2;
398 hscroll_req.height = 2;
399 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
400 (scroll_window->hscrollbar, &hscroll_req );
401
402 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
403
404 if (scroll_window->vscrollbar_visible)
405 {
406 dw += vscroll_req.width;
407 dw += scroll_class->scrollbar_spacing;
408 }
409
410 if (scroll_window->hscrollbar_visible)
411 {
412 dh += hscroll_req.height;
413 dh += scroll_class->scrollbar_spacing;
414 }
415 }
416
417 int dx = 0;
418 int dy = 0;
419 if (GTK_WIDGET_NO_WINDOW (widget))
420 {
421 dx += widget->allocation.x;
422 dy += widget->allocation.y;
423 }
424
425 if (win->HasFlag(wxRAISED_BORDER))
426 {
427 gtk_draw_shadow( widget->style,
428 widget->window,
429 GTK_STATE_NORMAL,
430 GTK_SHADOW_OUT,
431 dx, dy,
432 widget->allocation.width-dw, widget->allocation.height-dh );
433 return;
434 }
435
436 if (win->HasFlag(wxSUNKEN_BORDER))
437 {
438 gtk_draw_shadow( widget->style,
439 widget->window,
440 GTK_STATE_NORMAL,
441 GTK_SHADOW_IN,
442 dx, dy,
443 widget->allocation.width-dw, widget->allocation.height-dh );
444 return;
445 }
446
447 if (win->HasFlag(wxSIMPLE_BORDER))
448 {
449 GdkGC *gc;
450 gc = gdk_gc_new( widget->window );
451 gdk_gc_set_foreground( gc, &widget->style->black );
452 gdk_draw_rectangle( widget->window, gc, FALSE,
453 dx, dy,
454 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
455 gdk_gc_unref( gc );
456 return;
457 }
458 #endif // __WXUNIVERSAL__
459 }
460
461 //-----------------------------------------------------------------------------
462 // "expose_event" of m_widget
463 //-----------------------------------------------------------------------------
464
465 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
466 {
467 if (gdk_event->count > 0) return FALSE;
468
469 draw_frame( widget, win );
470
471 return TRUE;
472 }
473
474 //-----------------------------------------------------------------------------
475 // "draw" of m_widget
476 //-----------------------------------------------------------------------------
477
478 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
479 {
480 draw_frame( widget, win );
481 }
482
483 //-----------------------------------------------------------------------------
484 // key code mapping routines
485 //-----------------------------------------------------------------------------
486
487 static long map_to_unmodified_wx_keysym( GdkEventKey *event )
488 {
489 KeySym keysym = event->keyval;
490 long key_code;
491
492 switch (keysym)
493 {
494 case GDK_Shift_L:
495 case GDK_Shift_R: key_code = WXK_SHIFT; break;
496 case GDK_Control_L:
497 case GDK_Control_R: key_code = WXK_CONTROL; break;
498 case GDK_Meta_L:
499 case GDK_Meta_R:
500 case GDK_Alt_L:
501 case GDK_Alt_R:
502 case GDK_Super_L:
503 case GDK_Super_R: key_code = WXK_ALT; break;
504 case GDK_Menu: key_code = WXK_MENU; break;
505 case GDK_Help: key_code = WXK_HELP; break;
506 case GDK_BackSpace: key_code = WXK_BACK; break;
507 case GDK_ISO_Left_Tab:
508 case GDK_Tab: key_code = WXK_TAB; break;
509 case GDK_Linefeed: key_code = WXK_RETURN; break;
510 case GDK_Clear: key_code = WXK_CLEAR; break;
511 case GDK_Return: key_code = WXK_RETURN; break;
512 case GDK_Pause: key_code = WXK_PAUSE; break;
513 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
514 case GDK_Escape: key_code = WXK_ESCAPE; break;
515 case GDK_Delete: key_code = WXK_DELETE; break;
516 case GDK_Home: key_code = WXK_HOME; break;
517 case GDK_Left: key_code = WXK_LEFT; break;
518 case GDK_Up: key_code = WXK_UP; break;
519 case GDK_Right: key_code = WXK_RIGHT; break;
520 case GDK_Down: key_code = WXK_DOWN; break;
521 case GDK_Prior: key_code = WXK_PRIOR; break;
522 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
523 case GDK_Next: key_code = WXK_NEXT; break;
524 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
525 case GDK_End: key_code = WXK_END; break;
526 case GDK_Begin: key_code = WXK_HOME; break;
527 case GDK_Select: key_code = WXK_SELECT; break;
528 case GDK_Print: key_code = WXK_PRINT; break;
529 case GDK_Execute: key_code = WXK_EXECUTE; break;
530 case GDK_Insert: key_code = WXK_INSERT; break;
531 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
532
533 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
534 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
535 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
536 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
537 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
538 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
539 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
540 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
541 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
542 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
543 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
544 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
545 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
546 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
547 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
548 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
549 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
550 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
551 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
552 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
553 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
554 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
555 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
556 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
557 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
558 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
559 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
560 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
561 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
562 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
563 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
564 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
565 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
566 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
567 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
568 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
569 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
570
571 case GDK_F1: key_code = WXK_F1; break;
572 case GDK_F2: key_code = WXK_F2; break;
573 case GDK_F3: key_code = WXK_F3; break;
574 case GDK_F4: key_code = WXK_F4; break;
575 case GDK_F5: key_code = WXK_F5; break;
576 case GDK_F6: key_code = WXK_F6; break;
577 case GDK_F7: key_code = WXK_F7; break;
578 case GDK_F8: key_code = WXK_F8; break;
579 case GDK_F9: key_code = WXK_F9; break;
580 case GDK_F10: key_code = WXK_F10; break;
581 case GDK_F11: key_code = WXK_F11; break;
582 case GDK_F12: key_code = WXK_F12; break;
583 default:
584 if ( (keysym & 0xFF) == keysym )
585 {
586 guint upper = gdk_keyval_to_upper( (guint)keysym );
587 key_code = upper ? upper : keysym;
588 }
589 else
590 {
591 // unknown key code
592 key_code = 0;
593 }
594 }
595
596 return key_code;
597 }
598
599 static long map_to_wx_keysym( GdkEventKey *event )
600 {
601 KeySym keysym = event->keyval;
602 guint key_code = 0;
603
604 switch (keysym)
605 {
606 case GDK_Menu: key_code = WXK_MENU; break;
607 case GDK_Help: key_code = WXK_HELP; break;
608 case GDK_BackSpace: key_code = WXK_BACK; break;
609 case GDK_ISO_Left_Tab:
610 case GDK_Tab: key_code = WXK_TAB; break;
611 case GDK_Linefeed: key_code = WXK_RETURN; break;
612 case GDK_Clear: key_code = WXK_CLEAR; break;
613 case GDK_Return: key_code = WXK_RETURN; break;
614 case GDK_Pause: key_code = WXK_PAUSE; break;
615 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
616 case GDK_Escape: key_code = WXK_ESCAPE; break;
617 case GDK_Delete: key_code = WXK_DELETE; break;
618 case GDK_Home: key_code = WXK_HOME; break;
619 case GDK_Left: key_code = WXK_LEFT; break;
620 case GDK_Up: key_code = WXK_UP; break;
621 case GDK_Right: key_code = WXK_RIGHT; break;
622 case GDK_Down: key_code = WXK_DOWN; break;
623 case GDK_Prior: key_code = WXK_PRIOR; break;
624 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
625 case GDK_Next: key_code = WXK_NEXT; break;
626 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
627 case GDK_End: key_code = WXK_END; break;
628 case GDK_Begin: key_code = WXK_HOME; break;
629 case GDK_Select: key_code = WXK_SELECT; break;
630 case GDK_Print: key_code = WXK_PRINT; break;
631 case GDK_Execute: key_code = WXK_EXECUTE; break;
632 case GDK_Insert: key_code = WXK_INSERT; break;
633 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
634
635 case GDK_KP_0: key_code = '0'; break;
636 case GDK_KP_1: key_code = '1'; break;
637 case GDK_KP_2: key_code = '2'; break;
638 case GDK_KP_3: key_code = '3'; break;
639 case GDK_KP_4: key_code = '4'; break;
640 case GDK_KP_5: key_code = '5'; break;
641 case GDK_KP_6: key_code = '6'; break;
642 case GDK_KP_7: key_code = '7'; break;
643 case GDK_KP_8: key_code = '8'; break;
644 case GDK_KP_9: key_code = '9'; break;
645 case GDK_KP_Space: key_code = ' '; break;
646 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
647 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
648 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
649 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
650 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
651 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
652 case GDK_KP_Home: key_code = WXK_HOME; break;
653 case GDK_KP_Left: key_code = WXK_LEFT; break;
654 case GDK_KP_Up: key_code = WXK_UP; break;
655 case GDK_KP_Right: key_code = WXK_RIGHT; break;
656 case GDK_KP_Down: key_code = WXK_DOWN; break;
657 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
658 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
659 case GDK_KP_Next: key_code = WXK_NEXT; break;
660 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
661 case GDK_KP_End: key_code = WXK_END; break;
662 case GDK_KP_Begin: key_code = WXK_HOME; break;
663 case GDK_KP_Insert: key_code = WXK_INSERT; break;
664 case GDK_KP_Delete: key_code = WXK_DELETE; break;
665 case GDK_KP_Equal: key_code = '='; break;
666 case GDK_KP_Multiply: key_code = '*'; break;
667 case GDK_KP_Add: key_code = '+'; break;
668 case GDK_KP_Separator: key_code = ','; break;
669 case GDK_KP_Subtract: key_code = '-'; break;
670 case GDK_KP_Decimal: key_code = '.'; break;
671 case GDK_KP_Divide: key_code = '/'; break;
672
673 case GDK_F1: key_code = WXK_F1; break;
674 case GDK_F2: key_code = WXK_F2; break;
675 case GDK_F3: key_code = WXK_F3; break;
676 case GDK_F4: key_code = WXK_F4; break;
677 case GDK_F5: key_code = WXK_F5; break;
678 case GDK_F6: key_code = WXK_F6; break;
679 case GDK_F7: key_code = WXK_F7; break;
680 case GDK_F8: key_code = WXK_F8; break;
681 case GDK_F9: key_code = WXK_F9; break;
682 case GDK_F10: key_code = WXK_F10; break;
683 case GDK_F11: key_code = WXK_F11; break;
684 case GDK_F12: key_code = WXK_F12; break;
685 default:
686 {
687 if (event->length == 1)
688 {
689 key_code = (unsigned char)*event->string;
690 }
691 else if ((keysym & 0xFF) == keysym)
692 {
693 key_code = (guint)keysym;
694 }
695 }
696 }
697
698 return key_code;
699 }
700
701 //-----------------------------------------------------------------------------
702 // "size_request" of m_widget
703 //-----------------------------------------------------------------------------
704
705 static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
706 {
707 int w,h;
708 win->GetSize( &w, &h );
709 if (w < 2) w = 2;
710 if (h < 2) h = 2;
711
712 requisition->height = h;
713 requisition->width = w;
714 }
715
716 //-----------------------------------------------------------------------------
717 // "expose_event" of m_wxwindow
718 //-----------------------------------------------------------------------------
719
720 static int gtk_window_expose_callback( GtkWidget *widget,
721 GdkEventExpose *gdk_event,
722 wxWindow *win )
723 {
724 DEBUG_MAIN_THREAD
725
726 if (g_isIdle)
727 wxapp_install_idle_handler();
728
729 /*
730 if (win->GetName() == wxT("panel"))
731 {
732 wxPrintf( wxT("OnExpose from ") );
733 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
734 wxPrintf( win->GetClassInfo()->GetClassName() );
735 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
736 (int)gdk_event->area.y,
737 (int)gdk_event->area.width,
738 (int)gdk_event->area.height );
739 }
740 */
741
742 GtkPizza *pizza = GTK_PIZZA (widget);
743
744 if (win->GetThemeEnabled())
745 {
746 wxWindow *parent = win->GetParent();
747 while (parent && !parent->IsTopLevel())
748 parent = parent->GetParent();
749 if (!parent)
750 parent = win;
751
752 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
753 GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
754 }
755
756 win->GetUpdateRegion().Union( gdk_event->area.x,
757 gdk_event->area.y,
758 gdk_event->area.width,
759 gdk_event->area.height );
760
761 if (gdk_event->count == 0)
762 {
763 win->m_clipPaintRegion = TRUE;
764
765 wxWindowDC dc(win);
766 dc.SetClippingRegion(win->GetUpdateRegion());
767 wxEraseEvent eevent( win->GetId(), &dc );
768 eevent.SetEventObject( win );
769 #if 1
770 (void)win->GetEventHandler()->ProcessEvent(eevent);
771 #else // 0
772 if (!win->GetEventHandler()->ProcessEvent(eevent))
773 {
774 wxClientDC dc( win );
775 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
776 dc.SetPen( *wxTRANSPARENT_PEN );
777
778 wxRegionIterator upd( win->GetUpdateRegion() );
779 while (upd)
780 {
781 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
782 upd ++;
783 }
784 }
785 #endif // 1/0
786
787 wxNcPaintEvent eventNc( win->GetId() );
788 eventNc.SetEventObject( win );
789 win->GetEventHandler()->ProcessEvent( eventNc );
790
791 wxPaintEvent event( win->GetId() );
792 event.SetEventObject( win );
793 win->GetEventHandler()->ProcessEvent( event );
794
795 win->GetUpdateRegion().Clear();
796
797 win->m_clipPaintRegion = FALSE;
798 }
799
800 /* The following code will result in all window-less widgets
801 being redrawn if the wxWindows class is given a chance to
802 paint *anything* because it will then be allowed to paint
803 over the window-less widgets */
804 GList *children = pizza->children;
805 while (children)
806 {
807 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
808 children = children->next;
809
810 GdkEventExpose child_event = *gdk_event;
811
812 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
813 GTK_WIDGET_DRAWABLE (child->widget) /* &&
814 gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
815 {
816 child_event.area.x = child->widget->allocation.x;
817 child_event.area.y = child->widget->allocation.y;
818 child_event.area.width = child->widget->allocation.width;
819 child_event.area.height = child->widget->allocation.height;
820 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
821 }
822 }
823
824 return TRUE;
825 }
826
827 //-----------------------------------------------------------------------------
828 // "event" of m_wxwindow
829 //-----------------------------------------------------------------------------
830
831 /* GTK thinks it is clever and filters out a certain amount of "unneeded"
832 expose events. We need them, of course, so we override the main event
833 procedure in GtkWidget by giving our own handler for all system events.
834 There, we look for expose events ourselves whereas all other events are
835 handled normally. */
836
837 gint gtk_window_event_event_callback( GtkWidget *widget,
838 GdkEventExpose *event,
839 wxWindow *win )
840 {
841 if (event->type == GDK_EXPOSE)
842 {
843 gint ret = gtk_window_expose_callback( widget, event, win );
844 return ret;
845 }
846
847 return FALSE;
848 }
849
850 //-----------------------------------------------------------------------------
851 // "draw" of m_wxwindow
852 //-----------------------------------------------------------------------------
853
854 /* This callback is a complete replacement of the gtk_pizza_draw() function,
855 which disabled. */
856
857 static void gtk_window_draw_callback( GtkWidget *widget,
858 GdkRectangle *rect,
859 wxWindow *win )
860 {
861 DEBUG_MAIN_THREAD
862
863 if (g_isIdle)
864 wxapp_install_idle_handler();
865
866 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
867 (win->GetChildren().GetCount() == 0))
868 {
869 return;
870 }
871
872 /*
873 if (win->GetName() == wxT("panel"))
874 {
875 wxPrintf( wxT("OnDraw from ") );
876 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
877 wxPrintf( win->GetClassInfo()->GetClassName() );
878 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
879 (int)rect->y,
880 (int)rect->width,
881 (int)rect->height );
882 }
883 */
884
885 GtkPizza *pizza = GTK_PIZZA (widget);
886
887 if (win->GetThemeEnabled())
888 {
889 wxWindow *parent = win->GetParent();
890 while (parent && !parent->IsTopLevel())
891 parent = parent->GetParent();
892 if (!parent)
893 parent = win;
894
895 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
896 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
897 }
898
899
900 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
901 (pizza->clear_on_draw))
902 {
903 gdk_window_clear_area( pizza->bin_window,
904 rect->x, rect->y, rect->width, rect->height);
905 }
906
907 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
908
909 win->m_clipPaintRegion = TRUE;
910
911 wxWindowDC dc(win);
912 dc.SetClippingRegion(win->GetUpdateRegion());
913 wxEraseEvent eevent( win->GetId(), &dc );
914 eevent.SetEventObject( win );
915
916 #if 1
917 (void)win->GetEventHandler()->ProcessEvent(eevent);
918 #else
919 if (!win->GetEventHandler()->ProcessEvent(eevent))
920 {
921 if (!win->GetEventHandler()->ProcessEvent(eevent))
922 {
923 wxClientDC dc( win );
924 dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
925 dc.SetPen( *wxTRANSPARENT_PEN );
926
927 wxRegionIterator upd( win->GetUpdateRegion() );
928 while (upd)
929 {
930 dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
931 upd ++;
932 }
933 }
934 }
935 #endif
936
937 wxNcPaintEvent eventNc( win->GetId() );
938 eventNc.SetEventObject( win );
939 win->GetEventHandler()->ProcessEvent( eventNc );
940
941 wxPaintEvent event( win->GetId() );
942 event.SetEventObject( win );
943 win->GetEventHandler()->ProcessEvent( event );
944
945 win->GetUpdateRegion().Clear();
946
947 win->m_clipPaintRegion = FALSE;
948
949
950 GList *children = pizza->children;
951 while (children)
952 {
953 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
954 children = children->next;
955
956 GdkRectangle child_area;
957 if (gtk_widget_intersect (child->widget, rect, &child_area))
958 {
959 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
960 }
961 }
962 }
963
964 //-----------------------------------------------------------------------------
965 // "key_press_event" from any window
966 //-----------------------------------------------------------------------------
967
968 // turn on to see the key event codes on the console
969 #undef DEBUG_KEY_EVENTS
970
971 static gint gtk_window_key_press_callback( GtkWidget *widget,
972 GdkEventKey *gdk_event,
973 wxWindow *win )
974 {
975 DEBUG_MAIN_THREAD
976
977 if (g_isIdle)
978 wxapp_install_idle_handler();
979
980 if (!win->m_hasVMT) return FALSE;
981 if (g_blockEventsOnDrag) return FALSE;
982
983
984 int x = 0;
985 int y = 0;
986 GdkModifierType state;
987 if (gdk_event->window)
988 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
989
990 bool ret = FALSE;
991
992 long key_code = map_to_unmodified_wx_keysym( gdk_event );
993
994 #ifdef DEBUG_KEY_EVENTS
995 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
996 #endif // DEBUG_KEY_EVENTS
997
998 /* sending unknown key events doesn't really make sense */
999 if (key_code == 0)
1000 return FALSE;
1001
1002 wxKeyEvent event( wxEVT_KEY_DOWN );
1003 event.SetTimestamp( gdk_event->time );
1004 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1005 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1006 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1007 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1008 event.m_keyCode = key_code;
1009 event.m_scanCode = gdk_event->keyval;
1010 event.m_x = x;
1011 event.m_y = y;
1012 event.SetEventObject( win );
1013 ret = win->GetEventHandler()->ProcessEvent( event );
1014
1015 #if wxUSE_ACCEL
1016 if (!ret)
1017 {
1018 wxWindowGTK *ancestor = win;
1019 while (ancestor)
1020 {
1021 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1022 if (command != -1)
1023 {
1024 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1025 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1026 break;
1027 }
1028 if (ancestor->IsTopLevel())
1029 break;
1030 ancestor = ancestor->GetParent();
1031 }
1032 }
1033 #endif // wxUSE_ACCEL
1034
1035 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1036 will only be sent if it is not in an accelerator table. */
1037 if ( !ret )
1038 {
1039 key_code = map_to_wx_keysym( gdk_event );
1040
1041 if ( key_code )
1042 {
1043 #ifdef DEBUG_KEY_EVENTS
1044 wxPrintf(_T("Char event: %ld\n"), key_code);
1045 #endif // DEBUG_KEY_EVENTS
1046
1047 // reuse the ame event object, just change its type and use the
1048 // translated keycode instead of the raw one
1049 event.SetEventType(wxEVT_CHAR);
1050 event.m_keyCode = key_code;
1051
1052 ret = win->GetEventHandler()->ProcessEvent( event );
1053 }
1054 }
1055
1056 /* win is a control: tab can be propagated up */
1057 if ( !ret &&
1058 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1059 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1060 // have this style, yet choose not to process this particular TAB in which
1061 // case TAB must still work as a navigational character
1062 #if 0
1063 !win->HasFlag(wxTE_PROCESS_TAB) &&
1064 #endif // 0
1065 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1066 {
1067 wxNavigationKeyEvent new_event;
1068 new_event.SetEventObject( win->GetParent() );
1069 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1070 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1071 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1072 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1073 new_event.SetCurrentFocus( win );
1074 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1075 }
1076
1077 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1078 if ( !ret &&
1079 (gdk_event->keyval == GDK_Escape) )
1080 {
1081 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1082 new_event.SetEventObject( win );
1083 ret = win->GetEventHandler()->ProcessEvent( new_event );
1084 }
1085
1086 /* Doesn't work. */
1087 #if 0 // (GTK_MINOR_VERSION > 0)
1088 /* Pressing F10 will activate the menu bar of the top frame. */
1089 if ( (!ret) &&
1090 (gdk_event->keyval == GDK_F10) )
1091 {
1092 wxWindowGTK *ancestor = win;
1093 while (ancestor)
1094 {
1095 if (wxIsKindOf(ancestor,wxFrame))
1096 {
1097 wxFrame *frame = (wxFrame*) ancestor;
1098 wxMenuBar *menubar = frame->GetMenuBar();
1099 if (menubar)
1100 {
1101 wxNode *node = menubar->GetMenus().First();
1102 if (node)
1103 {
1104 wxMenu *firstMenu = (wxMenu*) node->Data();
1105 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1106 ret = TRUE;
1107 break;
1108 }
1109 }
1110 }
1111 ancestor = ancestor->GetParent();
1112 }
1113 }
1114 #endif // 0
1115
1116 if (ret)
1117 {
1118 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1119 return TRUE;
1120 }
1121
1122 return FALSE;
1123 }
1124
1125 //-----------------------------------------------------------------------------
1126 // "key_release_event" from any window
1127 //-----------------------------------------------------------------------------
1128
1129 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
1130 {
1131 DEBUG_MAIN_THREAD
1132
1133 if (g_isIdle)
1134 wxapp_install_idle_handler();
1135
1136 if (!win->m_hasVMT) return FALSE;
1137 if (g_blockEventsOnDrag) return FALSE;
1138
1139 long key_code = map_to_unmodified_wx_keysym( gdk_event );
1140
1141 #ifdef DEBUG_KEY_EVENTS
1142 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
1143 #endif // DEBUG_KEY_EVENTS
1144
1145 /* sending unknown key events doesn't really make sense */
1146 if (key_code == 0) return FALSE;
1147
1148 int x = 0;
1149 int y = 0;
1150 GdkModifierType state;
1151 if (gdk_event->window)
1152 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1153
1154 wxKeyEvent event( wxEVT_KEY_UP );
1155 event.SetTimestamp( gdk_event->time );
1156 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1157 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1158 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1159 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1160 event.m_keyCode = key_code;
1161 event.m_scanCode = gdk_event->keyval;
1162 event.m_x = x;
1163 event.m_y = y;
1164 event.SetEventObject( win );
1165
1166 if (win->GetEventHandler()->ProcessEvent( event ))
1167 {
1168 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1169 return TRUE;
1170 }
1171
1172 return FALSE;
1173 }
1174
1175 // ----------------------------------------------------------------------------
1176 // mouse event processing helper
1177 // ----------------------------------------------------------------------------
1178
1179 static void AdjustEventButtonState(wxMouseEvent& event)
1180 {
1181 // GDK reports the old state of the button for a button press event, but
1182 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1183 // for a LEFT_DOWN event, not FALSE, so we will invert
1184 // left/right/middleDown for the corresponding click events
1185
1186 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1187 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1188 (event.GetEventType() == wxEVT_LEFT_UP))
1189 {
1190 event.m_leftDown = !event.m_leftDown;
1191 return;
1192 }
1193
1194 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1195 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1196 (event.GetEventType() == wxEVT_MIDDLE_UP))
1197 {
1198 event.m_middleDown = !event.m_middleDown;
1199 return;
1200 }
1201
1202 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1203 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1204 (event.GetEventType() == wxEVT_RIGHT_UP))
1205 {
1206 event.m_rightDown = !event.m_rightDown;
1207 return;
1208 }
1209 }
1210
1211 //-----------------------------------------------------------------------------
1212 // "button_press_event"
1213 //-----------------------------------------------------------------------------
1214
1215 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1216 {
1217 DEBUG_MAIN_THREAD
1218
1219 if (g_isIdle)
1220 wxapp_install_idle_handler();
1221
1222 /*
1223 wxPrintf( wxT("1) OnButtonPress from ") );
1224 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1225 wxPrintf( win->GetClassInfo()->GetClassName() );
1226 wxPrintf( wxT(".\n") );
1227 */
1228 if (!win->m_hasVMT) return FALSE;
1229 if (g_blockEventsOnDrag) return TRUE;
1230 if (g_blockEventsOnScroll) return TRUE;
1231
1232 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1233
1234 if (win->m_wxwindow)
1235 {
1236 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1237 {
1238 gtk_widget_grab_focus (win->m_wxwindow);
1239
1240 /*
1241 wxPrintf( wxT("GrabFocus from ") );
1242 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1243 wxPrintf( win->GetClassInfo()->GetClassName() );
1244 wxPrintf( wxT(".\n") );
1245 */
1246
1247 }
1248 }
1249
1250 wxEventType event_type = wxEVT_NULL;
1251
1252 if (gdk_event->button == 1)
1253 {
1254 switch (gdk_event->type)
1255 {
1256 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1257 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1258 default: break;
1259 }
1260 }
1261 else if (gdk_event->button == 2)
1262 {
1263 switch (gdk_event->type)
1264 {
1265 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1266 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1267 default: break;
1268 }
1269 }
1270 else if (gdk_event->button == 3)
1271 {
1272 switch (gdk_event->type)
1273 {
1274 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1275 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1276 default: break;
1277 }
1278 }
1279
1280 if ( event_type == wxEVT_NULL )
1281 {
1282 // unknown mouse button or click type
1283 return FALSE;
1284 }
1285
1286 wxMouseEvent event( event_type );
1287 event.SetTimestamp( gdk_event->time );
1288 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1289 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1290 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1291 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1292 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1293 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1294 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1295
1296 event.m_x = (wxCoord)gdk_event->x;
1297 event.m_y = (wxCoord)gdk_event->y;
1298
1299 AdjustEventButtonState(event);
1300
1301 // Some control don't have their own X window and thus cannot get
1302 // any events.
1303
1304 if (!g_captureWindow)
1305 {
1306 wxCoord x = event.m_x;
1307 wxCoord y = event.m_y;
1308 if (win->m_wxwindow)
1309 {
1310 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1311 x += pizza->xoffset;
1312 y += pizza->yoffset;
1313 }
1314
1315 wxNode *node = win->GetChildren().First();
1316 while (node)
1317 {
1318 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1319
1320 node = node->Next();
1321 if (!child->IsShown())
1322 continue;
1323
1324 if (child->m_isStaticBox)
1325 {
1326 // wxStaticBox is transparent in the box itself
1327 int xx1 = child->m_x;
1328 int yy1 = child->m_y;
1329 int xx2 = child->m_x + child->m_width;
1330 int yy2 = child->m_x + child->m_height;
1331
1332 // left
1333 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1334 // right
1335 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1336 // top
1337 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1338 // bottom
1339 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1340 {
1341 win = child;
1342 event.m_x -= child->m_x;
1343 event.m_y -= child->m_y;
1344 break;
1345 }
1346
1347 }
1348 else
1349 {
1350 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1351 (child->m_x <= x) &&
1352 (child->m_y <= y) &&
1353 (child->m_x+child->m_width >= x) &&
1354 (child->m_y+child->m_height >= y))
1355 {
1356 win = child;
1357 event.m_x -= child->m_x;
1358 event.m_y -= child->m_y;
1359 break;
1360 }
1361 }
1362 }
1363 }
1364
1365 event.SetEventObject( win );
1366
1367 gs_timeLastClick = gdk_event->time;
1368
1369 /*
1370 wxPrintf( wxT("2) OnButtonPress from ") );
1371 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1372 wxPrintf( win->GetClassInfo()->GetClassName() );
1373 wxPrintf( wxT(".\n") );
1374 */
1375
1376 if (win->GetEventHandler()->ProcessEvent( event ))
1377 {
1378 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1379 return TRUE;
1380 }
1381
1382 return FALSE;
1383 }
1384
1385 //-----------------------------------------------------------------------------
1386 // "button_release_event"
1387 //-----------------------------------------------------------------------------
1388
1389 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
1390 {
1391 DEBUG_MAIN_THREAD
1392
1393 if (g_isIdle)
1394 wxapp_install_idle_handler();
1395
1396 if (!win->m_hasVMT) return FALSE;
1397 if (g_blockEventsOnDrag) return FALSE;
1398 if (g_blockEventsOnScroll) return FALSE;
1399
1400 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1401
1402 /*
1403 printf( "OnButtonRelease from " );
1404 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1405 printf( win->GetClassInfo()->GetClassName() );
1406 printf( ".\n" );
1407 */
1408
1409 wxEventType event_type = wxEVT_NULL;
1410
1411 switch (gdk_event->button)
1412 {
1413 case 1: event_type = wxEVT_LEFT_UP; break;
1414 case 2: event_type = wxEVT_MIDDLE_UP; break;
1415 case 3: event_type = wxEVT_RIGHT_UP; break;
1416 default: return FALSE;
1417 }
1418
1419 wxMouseEvent event( event_type );
1420 event.SetTimestamp( gdk_event->time );
1421 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1422 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1423 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1424 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1425 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1426 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1427 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1428 event.m_x = (wxCoord)gdk_event->x;
1429 event.m_y = (wxCoord)gdk_event->y;
1430
1431 AdjustEventButtonState(event);
1432
1433 // Some control don't have their own X window and thus cannot get
1434 // any events.
1435
1436 if (!g_captureWindow)
1437 {
1438 wxCoord x = event.m_x;
1439 wxCoord y = event.m_y;
1440 if (win->m_wxwindow)
1441 {
1442 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1443 x += pizza->xoffset;
1444 y += pizza->yoffset;
1445 }
1446
1447 wxNode *node = win->GetChildren().First();
1448 while (node)
1449 {
1450 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1451
1452 node = node->Next();
1453 if (!child->IsShown())
1454 continue;
1455
1456 if (child->m_isStaticBox)
1457 {
1458 // wxStaticBox is transparent in the box itself
1459 int xx1 = child->m_x;
1460 int yy1 = child->m_y;
1461 int xx2 = child->m_x + child->m_width;
1462 int yy2 = child->m_x + child->m_height;
1463
1464 // left
1465 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1466 // right
1467 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1468 // top
1469 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1470 // bottom
1471 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1472 {
1473 win = child;
1474 event.m_x -= child->m_x;
1475 event.m_y -= child->m_y;
1476 break;
1477 }
1478
1479 }
1480 else
1481 {
1482 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1483 (child->m_x <= x) &&
1484 (child->m_y <= y) &&
1485 (child->m_x+child->m_width >= x) &&
1486 (child->m_y+child->m_height >= y))
1487 {
1488 win = child;
1489 event.m_x -= child->m_x;
1490 event.m_y -= child->m_y;
1491 break;
1492 }
1493 }
1494 }
1495 }
1496
1497 event.SetEventObject( win );
1498
1499 if (win->GetEventHandler()->ProcessEvent( event ))
1500 {
1501 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1502 return TRUE;
1503 }
1504
1505 return FALSE;
1506 }
1507
1508 // ============================================================================
1509 // the mouse events
1510 // ============================================================================
1511
1512 // init wxMouseEvent with the info from gdk_event
1513 #define InitMouseEvent(event, gdk_event) \
1514 event.SetTimestamp( gdk_event->time ); \
1515 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1516 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1517 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1518 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1519 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1520 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1521 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1522 \
1523 event.m_x = (wxCoord)gdk_event->x; \
1524 event.m_y = (wxCoord)gdk_event->y \
1525
1526 //-----------------------------------------------------------------------------
1527 // "motion_notify_event"
1528 //-----------------------------------------------------------------------------
1529
1530 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1531 GdkEventMotion *gdk_event,
1532 wxWindowGTK *win )
1533 {
1534 DEBUG_MAIN_THREAD
1535
1536 if (g_isIdle)
1537 wxapp_install_idle_handler();
1538
1539 if (!win->m_hasVMT) return FALSE;
1540 if (g_blockEventsOnDrag) return FALSE;
1541 if (g_blockEventsOnScroll) return FALSE;
1542
1543 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1544
1545 if (gdk_event->is_hint)
1546 {
1547 int x = 0;
1548 int y = 0;
1549 GdkModifierType state;
1550 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1551 gdk_event->x = x;
1552 gdk_event->y = y;
1553 }
1554
1555 /*
1556 printf( "OnMotion from " );
1557 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1558 printf( win->GetClassInfo()->GetClassName() );
1559 printf( ".\n" );
1560 */
1561
1562 wxMouseEvent event( wxEVT_MOTION );
1563 InitMouseEvent(event, gdk_event);
1564
1565 if ( g_captureWindow )
1566 {
1567 // synthetize a mouse enter or leave event if needed
1568 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1569 bool hasMouse = winUnderMouse == gdk_event->window;
1570 if ( hasMouse != g_captureWindowHasMouse )
1571 {
1572 // the mouse changed window
1573 g_captureWindowHasMouse = hasMouse;
1574
1575 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1576 : wxEVT_LEAVE_WINDOW);
1577 InitMouseEvent(event, gdk_event);
1578 event.SetEventObject(win);
1579 win->GetEventHandler()->ProcessEvent(event);
1580 }
1581 }
1582 else // no capture
1583 {
1584 // Some control don't have their own X window and thus cannot get
1585 // any events.
1586
1587 wxCoord x = event.m_x;
1588 wxCoord y = event.m_y;
1589 if (win->m_wxwindow)
1590 {
1591 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1592 x += pizza->xoffset;
1593 y += pizza->yoffset;
1594 }
1595
1596 wxNode *node = win->GetChildren().First();
1597 while (node)
1598 {
1599 wxWindowGTK *child = (wxWindowGTK*)node->Data();
1600
1601 node = node->Next();
1602 if (!child->IsShown())
1603 continue;
1604
1605 if (child->m_isStaticBox)
1606 {
1607 // wxStaticBox is transparent in the box itself
1608 int xx1 = child->m_x;
1609 int yy1 = child->m_y;
1610 int xx2 = child->m_x + child->m_width;
1611 int yy2 = child->m_x + child->m_height;
1612
1613 // left
1614 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1615 // right
1616 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1617 // top
1618 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1619 // bottom
1620 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1621 {
1622 win = child;
1623 event.m_x -= child->m_x;
1624 event.m_y -= child->m_y;
1625 break;
1626 }
1627
1628 }
1629 else
1630 {
1631 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1632 (child->m_x <= x) &&
1633 (child->m_y <= y) &&
1634 (child->m_x+child->m_width >= x) &&
1635 (child->m_y+child->m_height >= y))
1636 {
1637 win = child;
1638 event.m_x -= child->m_x;
1639 event.m_y -= child->m_y;
1640 break;
1641 }
1642 }
1643 }
1644 }
1645
1646 event.SetEventObject( win );
1647
1648 if (win->GetEventHandler()->ProcessEvent( event ))
1649 {
1650 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1651 return TRUE;
1652 }
1653
1654 return FALSE;
1655 }
1656
1657 //-----------------------------------------------------------------------------
1658 // "focus_in_event"
1659 //-----------------------------------------------------------------------------
1660
1661 static gint gtk_window_focus_in_callback( GtkWidget *widget,
1662 GdkEvent *WXUNUSED(event),
1663 wxWindow *win )
1664 {
1665 DEBUG_MAIN_THREAD
1666
1667 if (g_isIdle)
1668 wxapp_install_idle_handler();
1669
1670 if (!win->m_hasVMT) return FALSE;
1671 if (g_blockEventsOnDrag) return FALSE;
1672
1673 switch ( g_sendActivateEvent )
1674 {
1675 case -1:
1676 // we've got focus from outside, synthetize wxActivateEvent
1677 g_sendActivateEvent = 1;
1678 break;
1679
1680 case 0:
1681 // another our window just lost focus, it was already ours before
1682 // - don't send any wxActivateEvent
1683 g_sendActivateEvent = -1;
1684 break;
1685 }
1686
1687 g_focusWindowLast =
1688 g_focusWindow = win;
1689
1690 #if 0
1691 wxPrintf( "OnSetFocus from " );
1692 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1693 wxPrintf( win->GetClassInfo()->GetClassName() );
1694 wxPrintf( ".\n" );
1695 #endif
1696
1697 // notify the parent keeping track of focus for the kbd navigation
1698 // purposes that we got it
1699 wxChildFocusEvent eventFocus(win);
1700 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
1701
1702 #ifdef HAVE_XIM
1703 if (win->m_ic)
1704 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1705 #endif
1706
1707 #if wxUSE_CARET
1708 // caret needs to be informed about focus change
1709 wxCaret *caret = win->GetCaret();
1710 if ( caret )
1711 {
1712 caret->OnSetFocus();
1713 }
1714 #endif // wxUSE_CARET
1715
1716
1717 wxWindowGTK *active = wxGetTopLevelParent(win);
1718 if ( active != g_activeFrame )
1719 {
1720 if ( g_activeFrame )
1721 {
1722 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
1723 event.SetEventObject(g_activeFrame);
1724 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1725 }
1726
1727 g_activeFrame = active;
1728 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
1729 event.SetEventObject(g_activeFrame);
1730 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1731 }
1732 g_activeFrameLostFocus = FALSE;
1733
1734
1735 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1736 event.SetEventObject( win );
1737
1738 if (win->GetEventHandler()->ProcessEvent( event ))
1739 {
1740 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1741 return TRUE;
1742 }
1743
1744
1745 return FALSE;
1746 }
1747
1748 //-----------------------------------------------------------------------------
1749 // "focus_out_event"
1750 //-----------------------------------------------------------------------------
1751
1752 static GtkWidget *gs_widgetLastFocus = NULL;
1753
1754 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
1755 {
1756 DEBUG_MAIN_THREAD
1757
1758 if (g_isIdle)
1759 wxapp_install_idle_handler();
1760
1761 if (!win->m_hasVMT) return FALSE;
1762 if (g_blockEventsOnDrag) return FALSE;
1763
1764 //wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
1765 g_activeFrameLostFocus = TRUE;
1766
1767 // VZ: this is really weird but GTK+ seems to call us from inside
1768 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1769 // this widget and then "focus_in". This is totally unexpected and
1770 // completely breaks wxUniv code so ignore this dummy event (we can't
1771 // be losing focus if we're about to acquire it!)
1772 if ( widget == gs_widgetLastFocus )
1773 {
1774 gs_widgetLastFocus = NULL;
1775
1776 return FALSE;
1777 }
1778
1779 // if the focus goes out of our app alltogether, OnIdle() will send
1780 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1781 // g_sendActivateEvent to -1
1782 g_sendActivateEvent = 0;
1783
1784 wxWindowGTK *winFocus = wxFindFocusedChild(win);
1785 if ( winFocus )
1786 win = winFocus;
1787
1788 g_focusWindow = (wxWindowGTK *)NULL;
1789
1790 #if 0
1791 wxPrintf( "OnKillFocus from " );
1792 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1793 wxPrintf( win->GetClassInfo()->GetClassName() );
1794 wxPrintf( ".\n" );
1795 #endif
1796
1797 #ifdef HAVE_XIM
1798 if (win->m_ic)
1799 gdk_im_end();
1800 #endif
1801
1802 #if wxUSE_CARET
1803 // caret needs to be informed about focus change
1804 wxCaret *caret = win->GetCaret();
1805 if ( caret )
1806 {
1807 caret->OnKillFocus();
1808 }
1809 #endif // wxUSE_CARET
1810
1811 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1812 event.SetEventObject( win );
1813
1814 if (win->GetEventHandler()->ProcessEvent( event ))
1815 {
1816 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1817 return TRUE;
1818 }
1819
1820 return FALSE;
1821 }
1822
1823 //-----------------------------------------------------------------------------
1824 // "enter_notify_event"
1825 //-----------------------------------------------------------------------------
1826
1827 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1828 {
1829 DEBUG_MAIN_THREAD
1830
1831 if (g_isIdle)
1832 wxapp_install_idle_handler();
1833
1834 if (!win->m_hasVMT) return FALSE;
1835 if (g_blockEventsOnDrag) return FALSE;
1836
1837 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1838
1839 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1840 event.SetTimestamp( gdk_event->time );
1841 event.SetEventObject( win );
1842
1843 int x = 0;
1844 int y = 0;
1845 GdkModifierType state = (GdkModifierType)0;
1846
1847 gdk_window_get_pointer( widget->window, &x, &y, &state );
1848
1849 InitMouseEvent(event, gdk_event);
1850
1851 event.m_x = x;
1852 event.m_y = y;
1853
1854 if (win->GetEventHandler()->ProcessEvent( event ))
1855 {
1856 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1857 return TRUE;
1858 }
1859
1860 return FALSE;
1861 }
1862
1863 //-----------------------------------------------------------------------------
1864 // "leave_notify_event"
1865 //-----------------------------------------------------------------------------
1866
1867 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1868 {
1869 DEBUG_MAIN_THREAD
1870
1871 if (g_isIdle)
1872 wxapp_install_idle_handler();
1873
1874 if (!win->m_hasVMT) return FALSE;
1875 if (g_blockEventsOnDrag) return FALSE;
1876
1877 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1878
1879 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1880 event.SetTimestamp( gdk_event->time );
1881 event.SetEventObject( win );
1882
1883 int x = 0;
1884 int y = 0;
1885 GdkModifierType state = (GdkModifierType)0;
1886
1887 gdk_window_get_pointer( widget->window, &x, &y, &state );
1888
1889 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1890 event.m_controlDown = (state & GDK_CONTROL_MASK);
1891 event.m_altDown = (state & GDK_MOD1_MASK);
1892 event.m_metaDown = (state & GDK_MOD2_MASK);
1893 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1894 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1895 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1896
1897 event.m_x = x;
1898 event.m_y = y;
1899
1900 if (win->GetEventHandler()->ProcessEvent( event ))
1901 {
1902 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1903 return TRUE;
1904 }
1905
1906 return FALSE;
1907 }
1908
1909 //-----------------------------------------------------------------------------
1910 // "value_changed" from m_vAdjust
1911 //-----------------------------------------------------------------------------
1912
1913 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1914 {
1915 DEBUG_MAIN_THREAD
1916
1917 if (g_isIdle)
1918 wxapp_install_idle_handler();
1919
1920 if (g_blockEventsOnDrag) return;
1921
1922 if (!win->m_hasVMT) return;
1923
1924 float diff = adjust->value - win->m_oldVerticalPos;
1925 if (fabs(diff) < 0.2) return;
1926
1927 win->m_oldVerticalPos = adjust->value;
1928
1929 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1930 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1931
1932 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1933 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1934 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1935 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1936 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1937
1938 int value = (int)(adjust->value+0.5);
1939
1940 wxScrollWinEvent event( command, value, wxVERTICAL );
1941 event.SetEventObject( win );
1942 win->GetEventHandler()->ProcessEvent( event );
1943 }
1944
1945 //-----------------------------------------------------------------------------
1946 // "value_changed" from m_hAdjust
1947 //-----------------------------------------------------------------------------
1948
1949 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
1950 {
1951 DEBUG_MAIN_THREAD
1952
1953 if (g_isIdle)
1954 wxapp_install_idle_handler();
1955
1956 if (g_blockEventsOnDrag) return;
1957 if (!win->m_hasVMT) return;
1958
1959 float diff = adjust->value - win->m_oldHorizontalPos;
1960 if (fabs(diff) < 0.2) return;
1961
1962 win->m_oldHorizontalPos = adjust->value;
1963
1964 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1965 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1966
1967 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1968 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1969 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1970 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1971 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1972
1973 int value = (int)(adjust->value+0.5);
1974
1975 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1976 event.SetEventObject( win );
1977 win->GetEventHandler()->ProcessEvent( event );
1978 }
1979
1980 //-----------------------------------------------------------------------------
1981 // "button_press_event" from scrollbar
1982 //-----------------------------------------------------------------------------
1983
1984 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1985 GdkEventButton *gdk_event,
1986 wxWindowGTK *win)
1987 {
1988 DEBUG_MAIN_THREAD
1989
1990 if (g_isIdle)
1991 wxapp_install_idle_handler();
1992
1993
1994 g_blockEventsOnScroll = TRUE;
1995 win->m_isScrolling = (gdk_event->window == widget->slider);
1996
1997 return FALSE;
1998 }
1999
2000 //-----------------------------------------------------------------------------
2001 // "button_release_event" from scrollbar
2002 //-----------------------------------------------------------------------------
2003
2004 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2005 GdkEventButton *WXUNUSED(gdk_event),
2006 wxWindowGTK *win)
2007 {
2008 DEBUG_MAIN_THREAD
2009
2010 // don't test here as we can release the mouse while being over
2011 // a different window than the slider
2012 //
2013 // if (gdk_event->window != widget->slider) return FALSE;
2014
2015 g_blockEventsOnScroll = FALSE;
2016
2017 if (win->m_isScrolling)
2018 {
2019 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2020 int value = -1;
2021 int dir = -1;
2022
2023 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2024 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2025 {
2026 value = (int)(win->m_hAdjust->value+0.5);
2027 dir = wxHORIZONTAL;
2028 }
2029 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2030 {
2031 value = (int)(win->m_vAdjust->value+0.5);
2032 dir = wxVERTICAL;
2033 }
2034
2035 wxScrollWinEvent event( command, value, dir );
2036 event.SetEventObject( win );
2037 win->GetEventHandler()->ProcessEvent( event );
2038 }
2039
2040 win->m_isScrolling = FALSE;
2041
2042 return FALSE;
2043 }
2044
2045 // ----------------------------------------------------------------------------
2046 // this wxWindowBase function is implemented here (in platform-specific file)
2047 // because it is static and so couldn't be made virtual
2048 // ----------------------------------------------------------------------------
2049
2050 wxWindow *wxWindowBase::FindFocus()
2051 {
2052 // the cast is necessary when we compile in wxUniversal mode
2053 return (wxWindow *)g_focusWindow;
2054 }
2055
2056 //-----------------------------------------------------------------------------
2057 // "realize" from m_widget
2058 //-----------------------------------------------------------------------------
2059
2060 /* We cannot set colours and fonts before the widget has
2061 been realized, so we do this directly after realization. */
2062
2063 static gint
2064 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
2065 {
2066 DEBUG_MAIN_THREAD
2067
2068 if (g_isIdle)
2069 wxapp_install_idle_handler();
2070
2071 if (win->m_delayedBackgroundColour)
2072 win->SetBackgroundColour( win->GetBackgroundColour() );
2073
2074 if (win->m_delayedForegroundColour)
2075 win->SetForegroundColour( win->GetForegroundColour() );
2076
2077 wxWindowCreateEvent event( win );
2078 event.SetEventObject( win );
2079 win->GetEventHandler()->ProcessEvent( event );
2080
2081 return FALSE;
2082 }
2083
2084 //-----------------------------------------------------------------------------
2085 // "size_allocate"
2086 //-----------------------------------------------------------------------------
2087
2088 static
2089 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2090 GtkAllocation *WXUNUSED(alloc),
2091 wxWindow *win )
2092 {
2093 if (g_isIdle)
2094 wxapp_install_idle_handler();
2095
2096 if (!win->m_hasScrolling) return;
2097
2098 int client_width = 0;
2099 int client_height = 0;
2100 win->GetClientSize( &client_width, &client_height );
2101 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2102 return;
2103
2104 win->m_oldClientWidth = client_width;
2105 win->m_oldClientHeight = client_height;
2106
2107 if (!win->m_nativeSizeEvent)
2108 {
2109 wxSizeEvent event( win->GetSize(), win->GetId() );
2110 event.SetEventObject( win );
2111 win->GetEventHandler()->ProcessEvent( event );
2112 }
2113 }
2114
2115
2116 #ifdef HAVE_XIM
2117 #define WXUNUSED_UNLESS_XIM(param) param
2118 #else
2119 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2120 #endif
2121
2122 /* Resize XIM window */
2123
2124 static
2125 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2126 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2127 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2128 {
2129 if (g_isIdle)
2130 wxapp_install_idle_handler();
2131
2132 #ifdef HAVE_XIM
2133 if (!win->m_ic)
2134 return;
2135
2136 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2137 {
2138 gint width, height;
2139
2140 gdk_window_get_size (widget->window, &width, &height);
2141 win->m_icattr->preedit_area.width = width;
2142 win->m_icattr->preedit_area.height = height;
2143 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2144 }
2145 #endif // HAVE_XIM
2146 }
2147
2148 //-----------------------------------------------------------------------------
2149 // "realize" from m_wxwindow
2150 //-----------------------------------------------------------------------------
2151
2152 /* Initialize XIM support */
2153
2154 static gint
2155 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2156 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2157 {
2158 if (g_isIdle)
2159 wxapp_install_idle_handler();
2160
2161 #ifdef HAVE_XIM
2162 if (win->m_ic) return FALSE;
2163 if (!widget) return FALSE;
2164 if (!gdk_im_ready()) return FALSE;
2165
2166 win->m_icattr = gdk_ic_attr_new();
2167 if (!win->m_icattr) return FALSE;
2168
2169 gint width, height;
2170 GdkEventMask mask;
2171 GdkColormap *colormap;
2172 GdkICAttr *attr = win->m_icattr;
2173 unsigned attrmask = GDK_IC_ALL_REQ;
2174 GdkIMStyle style;
2175 GdkIMStyle supported_style = (GdkIMStyle)
2176 (GDK_IM_PREEDIT_NONE |
2177 GDK_IM_PREEDIT_NOTHING |
2178 GDK_IM_PREEDIT_POSITION |
2179 GDK_IM_STATUS_NONE |
2180 GDK_IM_STATUS_NOTHING);
2181
2182 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2183 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2184
2185 attr->style = style = gdk_im_decide_style (supported_style);
2186 attr->client_window = widget->window;
2187
2188 if ((colormap = gtk_widget_get_colormap (widget)) !=
2189 gtk_widget_get_default_colormap ())
2190 {
2191 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2192 attr->preedit_colormap = colormap;
2193 }
2194
2195 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2196 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2197 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2198 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2199
2200 switch (style & GDK_IM_PREEDIT_MASK)
2201 {
2202 case GDK_IM_PREEDIT_POSITION:
2203 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2204 {
2205 g_warning ("over-the-spot style requires fontset");
2206 break;
2207 }
2208
2209 gdk_window_get_size (widget->window, &width, &height);
2210
2211 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2212 attr->spot_location.x = 0;
2213 attr->spot_location.y = height;
2214 attr->preedit_area.x = 0;
2215 attr->preedit_area.y = 0;
2216 attr->preedit_area.width = width;
2217 attr->preedit_area.height = height;
2218 attr->preedit_fontset = widget->style->font;
2219
2220 break;
2221 }
2222
2223 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2224
2225 if (win->m_ic == NULL)
2226 g_warning ("Can't create input context.");
2227 else
2228 {
2229 mask = gdk_window_get_events (widget->window);
2230 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2231 gdk_window_set_events (widget->window, mask);
2232
2233 if (GTK_WIDGET_HAS_FOCUS(widget))
2234 gdk_im_begin (win->m_ic, widget->window);
2235 }
2236 #endif // HAVE_XIM
2237
2238 return FALSE;
2239 }
2240
2241 //-----------------------------------------------------------------------------
2242 // InsertChild for wxWindowGTK.
2243 //-----------------------------------------------------------------------------
2244
2245 /* Callback for wxWindowGTK. This very strange beast has to be used because
2246 * C++ has no virtual methods in a constructor. We have to emulate a
2247 * virtual function here as wxNotebook requires a different way to insert
2248 * a child in it. I had opted for creating a wxNotebookPage window class
2249 * which would have made this superfluous (such in the MDI window system),
2250 * but no-one was listening to me... */
2251
2252 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2253 {
2254 /* the window might have been scrolled already, do we
2255 have to adapt the position */
2256 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2257 child->m_x += pizza->xoffset;
2258 child->m_y += pizza->yoffset;
2259
2260 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2261 GTK_WIDGET(child->m_widget),
2262 child->m_x,
2263 child->m_y,
2264 child->m_width,
2265 child->m_height );
2266 }
2267
2268 //-----------------------------------------------------------------------------
2269 // global functions
2270 //-----------------------------------------------------------------------------
2271
2272 wxWindow *wxGetActiveWindow()
2273 {
2274 // the cast is necessary when we compile in wxUniversal mode
2275 return (wxWindow *)g_focusWindow;
2276 }
2277
2278 //-----------------------------------------------------------------------------
2279 // wxWindowGTK
2280 //-----------------------------------------------------------------------------
2281
2282 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2283 // method
2284 #ifdef __WXUNIVERSAL__
2285 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2286 #else // __WXGTK__
2287 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2288 #endif // __WXUNIVERSAL__/__WXGTK__
2289
2290 void wxWindowGTK::Init()
2291 {
2292 // common init
2293 InitBase();
2294
2295 // GTK specific
2296 m_widget = (GtkWidget *) NULL;
2297 m_wxwindow = (GtkWidget *) NULL;
2298 m_focusWidget = (GtkWidget *) NULL;
2299
2300 // position/size
2301 m_x = 0;
2302 m_y = 0;
2303 m_width = 0;
2304 m_height = 0;
2305
2306 m_sizeSet = FALSE;
2307 m_hasVMT = FALSE;
2308 m_needParent = TRUE;
2309 m_isBeingDeleted = FALSE;
2310
2311 m_noExpose = FALSE;
2312 m_nativeSizeEvent = FALSE;
2313
2314 m_hasScrolling = FALSE;
2315 m_isScrolling = FALSE;
2316
2317 m_hAdjust = (GtkAdjustment*) NULL;
2318 m_vAdjust = (GtkAdjustment*) NULL;
2319 m_oldHorizontalPos = 0.0;
2320 m_oldVerticalPos = 0.0;
2321
2322 m_resizing = FALSE;
2323 m_widgetStyle = (GtkStyle*) NULL;
2324
2325 m_insertCallback = (wxInsertChildFunction) NULL;
2326
2327 m_isStaticBox = FALSE;
2328 m_isRadioButton = FALSE;
2329 m_isFrame = FALSE;
2330 m_acceptsFocus = FALSE;
2331
2332 m_clipPaintRegion = FALSE;
2333
2334 m_cursor = *wxSTANDARD_CURSOR;
2335
2336 m_delayedForegroundColour = FALSE;
2337 m_delayedBackgroundColour = FALSE;
2338
2339 #ifdef HAVE_XIM
2340 m_ic = (GdkIC*) NULL;
2341 m_icattr = (GdkICAttr*) NULL;
2342 #endif
2343 }
2344
2345 wxWindowGTK::wxWindowGTK()
2346 {
2347 Init();
2348 }
2349
2350 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2351 wxWindowID id,
2352 const wxPoint &pos,
2353 const wxSize &size,
2354 long style,
2355 const wxString &name )
2356 {
2357 Init();
2358
2359 Create( parent, id, pos, size, style, name );
2360 }
2361
2362 bool wxWindowGTK::Create( wxWindow *parent,
2363 wxWindowID id,
2364 const wxPoint &pos,
2365 const wxSize &size,
2366 long style,
2367 const wxString &name )
2368 {
2369 if (!PreCreation( parent, pos, size ) ||
2370 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2371 {
2372 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2373 return FALSE;
2374 }
2375
2376 m_insertCallback = wxInsertChildInWindow;
2377
2378 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2379 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2380
2381 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2382
2383 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2384 scroll_class->scrollbar_spacing = 0;
2385
2386 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2387
2388 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2389 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2390
2391 m_wxwindow = gtk_pizza_new();
2392
2393 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2394
2395 #ifndef __WXUNIVERSAL__
2396 #if (GTK_MINOR_VERSION > 0)
2397 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2398
2399 if (HasFlag(wxRAISED_BORDER))
2400 {
2401 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2402 }
2403 else if (HasFlag(wxSUNKEN_BORDER))
2404 {
2405 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2406 }
2407 else if (HasFlag(wxSIMPLE_BORDER))
2408 {
2409 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2410 }
2411 else
2412 {
2413 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2414 }
2415 #else // GTK_MINOR_VERSION == 0
2416 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2417
2418 if (HasFlag(wxRAISED_BORDER))
2419 {
2420 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2421 }
2422 else if (HasFlag(wxSUNKEN_BORDER))
2423 {
2424 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2425 }
2426 else
2427 {
2428 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2429 }
2430 #endif // GTK_MINOR_VERSION
2431 #endif // __WXUNIVERSAL__
2432
2433 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2434 m_acceptsFocus = TRUE;
2435
2436 #if (GTK_MINOR_VERSION == 0)
2437 // shut the viewport up
2438 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2439 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2440 #endif // GTK_MINOR_VERSION == 0
2441
2442 // I _really_ don't want scrollbars in the beginning
2443 m_vAdjust->lower = 0.0;
2444 m_vAdjust->upper = 1.0;
2445 m_vAdjust->value = 0.0;
2446 m_vAdjust->step_increment = 1.0;
2447 m_vAdjust->page_increment = 1.0;
2448 m_vAdjust->page_size = 5.0;
2449 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2450 m_hAdjust->lower = 0.0;
2451 m_hAdjust->upper = 1.0;
2452 m_hAdjust->value = 0.0;
2453 m_hAdjust->step_increment = 1.0;
2454 m_hAdjust->page_increment = 1.0;
2455 m_hAdjust->page_size = 5.0;
2456 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2457
2458 // these handlers block mouse events to any window during scrolling such as
2459 // motion events and prevent GTK and wxWindows from fighting over where the
2460 // slider should be
2461
2462 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2463 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2464
2465 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2466 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2467
2468 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2469 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2470
2471 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2472 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2473
2474 // these handlers get notified when screen updates are required either when
2475 // scrolling or when the window size (and therefore scrollbar configuration)
2476 // has changed
2477
2478 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2479 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2480 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2481 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2482
2483 gtk_widget_show( m_wxwindow );
2484
2485 if (m_parent)
2486 m_parent->DoAddChild( this );
2487
2488 m_focusWidget = m_wxwindow;
2489
2490 PostCreation();
2491
2492 Show( TRUE );
2493
2494 return TRUE;
2495 }
2496
2497 wxWindowGTK::~wxWindowGTK()
2498 {
2499 if (g_focusWindow == this)
2500 g_focusWindow = NULL;
2501
2502 if (g_activeFrame == this)
2503 g_activeFrame = NULL;
2504
2505 m_isBeingDeleted = TRUE;
2506 m_hasVMT = FALSE;
2507
2508 if (m_widget)
2509 Show( FALSE );
2510
2511 DestroyChildren();
2512
2513 if (m_parent)
2514 m_parent->RemoveChild( this );
2515
2516 #ifdef HAVE_XIM
2517 if (m_ic)
2518 gdk_ic_destroy (m_ic);
2519 if (m_icattr)
2520 gdk_ic_attr_destroy (m_icattr);
2521 #endif
2522
2523 if (m_widgetStyle)
2524 {
2525 #if DISABLE_STYLE_IF_BROKEN_THEME
2526 // don't delete if it's a pixmap theme style
2527 if (!m_widgetStyle->engine_data)
2528 gtk_style_unref( m_widgetStyle );
2529 #endif
2530 m_widgetStyle = (GtkStyle*) NULL;
2531 }
2532
2533 if (m_wxwindow)
2534 {
2535 gtk_widget_destroy( m_wxwindow );
2536 m_wxwindow = (GtkWidget*) NULL;
2537 }
2538
2539 if (m_widget)
2540 {
2541 gtk_widget_destroy( m_widget );
2542 m_widget = (GtkWidget*) NULL;
2543 }
2544 }
2545
2546 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2547 {
2548 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2549
2550 /* this turns -1 into 20 so that a minimal window is
2551 visible even although -1,-1 has been given as the
2552 size of the window. the same trick is used in other
2553 ports and should make debugging easier */
2554 m_width = WidthDefault(size.x);
2555 m_height = HeightDefault(size.y);
2556
2557 m_x = (int)pos.x;
2558 m_y = (int)pos.y;
2559
2560 /* some reasonable defaults */
2561 if (!parent)
2562 {
2563 if (m_x == -1)
2564 {
2565 m_x = (gdk_screen_width () - m_width) / 2;
2566 if (m_x < 10) m_x = 10;
2567 }
2568 if (m_y == -1)
2569 {
2570 m_y = (gdk_screen_height () - m_height) / 2;
2571 if (m_y < 10) m_y = 10;
2572 }
2573 }
2574
2575 return TRUE;
2576 }
2577
2578 void wxWindowGTK::PostCreation()
2579 {
2580 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2581
2582 if (m_wxwindow)
2583 {
2584 if (!m_noExpose)
2585 {
2586 // these get reported to wxWindows -> wxPaintEvent
2587
2588 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2589
2590 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2591 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2592
2593 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2594 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2595
2596 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2597 {
2598 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2599 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2600 }
2601 }
2602
2603 // these are called when the "sunken" or "raised" borders are drawn */
2604 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2605 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2606
2607 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2608 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2609 }
2610
2611 // focus handling
2612
2613 if (m_focusWidget == NULL)
2614 m_focusWidget = m_widget;
2615
2616 #if 0
2617 if (GetClassInfo() && GetClassInfo()->GetClassName())
2618 wxPrintf( GetClassInfo()->GetClassName() );
2619 wxPrintf( ".\n" );
2620 #endif
2621
2622 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2623 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2624
2625 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2626 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2627
2628 // connect to the various key and mouse handlers
2629
2630 GtkWidget *connect_widget = GetConnectWidget();
2631
2632 ConnectWidget( connect_widget );
2633
2634 /* We cannot set colours, fonts and cursors before the widget has
2635 been realized, so we do this directly after realization */
2636 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2637 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2638
2639 if (m_wxwindow)
2640 {
2641 // Catch native resize events
2642 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2643 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2644
2645 // Initialize XIM support
2646 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2647 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2648
2649 // And resize XIM window
2650 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2651 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2652 }
2653
2654 if (!GTK_IS_COMBO(m_widget))
2655 {
2656 // This is needed if we want to add our windows into native
2657 // GTK control, such as the toolbar. With this callback, the
2658 // toolbar gets to know the correct size (the one set by the
2659 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2660 // when moving to GTK 2.0.
2661 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2662 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2663 }
2664
2665 m_hasVMT = TRUE;
2666 }
2667
2668 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2669 {
2670 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2671 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2672
2673 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2674 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2675
2676 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2677 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2678
2679 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2680 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2681
2682 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2683 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2684
2685 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2686 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2687
2688 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2689 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2690 }
2691
2692 bool wxWindowGTK::Destroy()
2693 {
2694 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2695
2696 m_hasVMT = FALSE;
2697
2698 return wxWindowBase::Destroy();
2699 }
2700
2701 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2702 {
2703 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2704 }
2705
2706 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2707 {
2708 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2709 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2710
2711 /*
2712 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2713 */
2714
2715 if (m_resizing) return; /* I don't like recursions */
2716 m_resizing = TRUE;
2717
2718 int currentX, currentY;
2719 GetPosition(&currentX, &currentY);
2720 if (x == -1)
2721 x = currentX;
2722 if (y == -1)
2723 y = currentY;
2724 AdjustForParentClientOrigin(x, y, sizeFlags);
2725
2726 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2727 {
2728 /* don't set the size for children of wxNotebook, just take the values. */
2729 m_x = x;
2730 m_y = y;
2731 m_width = width;
2732 m_height = height;
2733 }
2734 else
2735 {
2736 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2737
2738 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2739 {
2740 if (x != -1) m_x = x + pizza->xoffset;
2741 if (y != -1) m_y = y + pizza->yoffset;
2742 if (width != -1) m_width = width;
2743 if (height != -1) m_height = height;
2744 }
2745 else
2746 {
2747 m_x = x + pizza->xoffset;
2748 m_y = y + pizza->yoffset;
2749 m_width = width;
2750 m_height = height;
2751 }
2752
2753 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2754 {
2755 if (width == -1) m_width = 80;
2756 }
2757
2758 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2759 {
2760 if (height == -1) m_height = 26;
2761 }
2762
2763 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2764 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2765 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2766 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2767
2768 int border = 0;
2769 int bottom_border = 0;
2770
2771 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2772 {
2773 /* the default button has a border around it */
2774 border = 6;
2775 bottom_border = 5;
2776 }
2777
2778 DoMoveWindow( m_x-border,
2779 m_y-border,
2780 m_width+2*border,
2781 m_height+border+bottom_border );
2782 }
2783
2784 if (m_hasScrolling)
2785 {
2786 /* Sometimes the client area changes size without the
2787 whole windows's size changing, but if the whole
2788 windows's size doesn't change, no wxSizeEvent will
2789 normally be sent. Here we add an extra test if
2790 the client test has been changed and this will
2791 be used then. */
2792 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2793 }
2794
2795 /*
2796 wxPrintf( "OnSize sent from " );
2797 if (GetClassInfo() && GetClassInfo()->GetClassName())
2798 wxPrintf( GetClassInfo()->GetClassName() );
2799 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2800 */
2801
2802 if (!m_nativeSizeEvent)
2803 {
2804 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2805 event.SetEventObject( this );
2806 GetEventHandler()->ProcessEvent( event );
2807 }
2808
2809 m_resizing = FALSE;
2810 }
2811
2812 void wxWindowGTK::OnInternalIdle()
2813 {
2814 if ( g_sendActivateEvent != -1 )
2815 {
2816 bool activate = g_sendActivateEvent != 0;
2817
2818 // do it only once
2819 g_sendActivateEvent = -1;
2820
2821 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
2822 }
2823
2824 if ( g_activeFrameLostFocus )
2825 {
2826 if ( g_activeFrame )
2827 {
2828 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
2829 event.SetEventObject(g_activeFrame);
2830 g_activeFrame->GetEventHandler()->ProcessEvent(event);
2831 g_activeFrame = NULL;
2832 }
2833 g_activeFrameLostFocus = FALSE;
2834 }
2835
2836 wxCursor cursor = m_cursor;
2837 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2838
2839 if (cursor.Ok())
2840 {
2841 /* I now set the cursor anew in every OnInternalIdle call
2842 as setting the cursor in a parent window also effects the
2843 windows above so that checking for the current cursor is
2844 not possible. */
2845
2846 if (m_wxwindow)
2847 {
2848 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2849 if (window)
2850 gdk_window_set_cursor( window, cursor.GetCursor() );
2851
2852 if (!g_globalCursor.Ok())
2853 cursor = *wxSTANDARD_CURSOR;
2854
2855 window = m_widget->window;
2856 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2857 gdk_window_set_cursor( window, cursor.GetCursor() );
2858
2859 }
2860 else
2861 {
2862
2863 GdkWindow *window = m_widget->window;
2864 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2865 gdk_window_set_cursor( window, cursor.GetCursor() );
2866
2867 }
2868 }
2869
2870 UpdateWindowUI();
2871 }
2872
2873 void wxWindowGTK::DoGetSize( int *width, int *height ) const
2874 {
2875 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2876
2877 if (width) (*width) = m_width;
2878 if (height) (*height) = m_height;
2879 }
2880
2881 void wxWindowGTK::DoSetClientSize( int width, int height )
2882 {
2883 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2884
2885 if (!m_wxwindow)
2886 {
2887 SetSize( width, height );
2888 }
2889 else
2890 {
2891 int dw = 0;
2892 int dh = 0;
2893
2894 #ifndef __WXUNIVERSAL__
2895 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2896 {
2897 /* when using GTK 1.2 we set the shadow border size to 2 */
2898 dw += 2 * 2;
2899 dh += 2 * 2;
2900 }
2901 if (HasFlag(wxSIMPLE_BORDER))
2902 {
2903 /* when using GTK 1.2 we set the simple border size to 1 */
2904 dw += 1 * 2;
2905 dh += 1 * 2;
2906 }
2907 #endif // __WXUNIVERSAL__
2908
2909 if (m_hasScrolling)
2910 {
2911 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2912
2913 GtkRequisition vscroll_req;
2914 vscroll_req.width = 2;
2915 vscroll_req.height = 2;
2916 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2917 (scroll_window->vscrollbar, &vscroll_req );
2918
2919 GtkRequisition hscroll_req;
2920 hscroll_req.width = 2;
2921 hscroll_req.height = 2;
2922 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2923 (scroll_window->hscrollbar, &hscroll_req );
2924
2925 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2926
2927 if (scroll_window->vscrollbar_visible)
2928 {
2929 dw += vscroll_req.width;
2930 dw += scroll_class->scrollbar_spacing;
2931 }
2932
2933 if (scroll_window->hscrollbar_visible)
2934 {
2935 dh += hscroll_req.height;
2936 dh += scroll_class->scrollbar_spacing;
2937 }
2938 }
2939
2940 SetSize( width+dw, height+dh );
2941 }
2942 }
2943
2944 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
2945 {
2946 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2947
2948 if (!m_wxwindow)
2949 {
2950 if (width) (*width) = m_width;
2951 if (height) (*height) = m_height;
2952 }
2953 else
2954 {
2955 int dw = 0;
2956 int dh = 0;
2957
2958 #ifndef __WXUNIVERSAL__
2959 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2960 {
2961 /* when using GTK 1.2 we set the shadow border size to 2 */
2962 dw += 2 * 2;
2963 dh += 2 * 2;
2964 }
2965 if (HasFlag(wxSIMPLE_BORDER))
2966 {
2967 /* when using GTK 1.2 we set the simple border size to 1 */
2968 dw += 1 * 2;
2969 dh += 1 * 2;
2970 }
2971 #endif // __WXUNIVERSAL__
2972
2973 if (m_hasScrolling)
2974 {
2975 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2976
2977 GtkRequisition vscroll_req;
2978 vscroll_req.width = 2;
2979 vscroll_req.height = 2;
2980 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2981 (scroll_window->vscrollbar, &vscroll_req );
2982
2983 GtkRequisition hscroll_req;
2984 hscroll_req.width = 2;
2985 hscroll_req.height = 2;
2986 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2987 (scroll_window->hscrollbar, &hscroll_req );
2988
2989 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2990
2991 if (scroll_window->vscrollbar_visible)
2992 {
2993 dw += vscroll_req.width;
2994 dw += scroll_class->scrollbar_spacing;
2995 }
2996
2997 if (scroll_window->hscrollbar_visible)
2998 {
2999 dh += hscroll_req.height;
3000 dh += scroll_class->scrollbar_spacing;
3001 }
3002 }
3003
3004 if (width) (*width) = m_width - dw;
3005 if (height) (*height) = m_height - dh;
3006 }
3007
3008 /*
3009 printf( "GetClientSize, name %s ", GetName().c_str() );
3010 if (width) printf( " width = %d", (*width) );
3011 if (height) printf( " height = %d", (*height) );
3012 printf( "\n" );
3013 */
3014 }
3015
3016 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3017 {
3018 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3019
3020 int dx = 0;
3021 int dy = 0;
3022 if (m_parent && m_parent->m_wxwindow)
3023 {
3024 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3025 dx = pizza->xoffset;
3026 dy = pizza->yoffset;
3027 }
3028
3029 if (x) (*x) = m_x - dx;
3030 if (y) (*y) = m_y - dy;
3031 }
3032
3033 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3034 {
3035 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3036
3037 if (!m_widget->window) return;
3038
3039 GdkWindow *source = (GdkWindow *) NULL;
3040 if (m_wxwindow)
3041 source = GTK_PIZZA(m_wxwindow)->bin_window;
3042 else
3043 source = m_widget->window;
3044
3045 int org_x = 0;
3046 int org_y = 0;
3047 gdk_window_get_origin( source, &org_x, &org_y );
3048
3049 if (!m_wxwindow)
3050 {
3051 if (GTK_WIDGET_NO_WINDOW (m_widget))
3052 {
3053 org_x += m_widget->allocation.x;
3054 org_y += m_widget->allocation.y;
3055 }
3056 }
3057
3058 if (x) *x += org_x;
3059 if (y) *y += org_y;
3060 }
3061
3062 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3063 {
3064 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3065
3066 if (!m_widget->window) return;
3067
3068 GdkWindow *source = (GdkWindow *) NULL;
3069 if (m_wxwindow)
3070 source = GTK_PIZZA(m_wxwindow)->bin_window;
3071 else
3072 source = m_widget->window;
3073
3074 int org_x = 0;
3075 int org_y = 0;
3076 gdk_window_get_origin( source, &org_x, &org_y );
3077
3078 if (!m_wxwindow)
3079 {
3080 if (GTK_WIDGET_NO_WINDOW (m_widget))
3081 {
3082 org_x += m_widget->allocation.x;
3083 org_y += m_widget->allocation.y;
3084 }
3085 }
3086
3087 if (x) *x -= org_x;
3088 if (y) *y -= org_y;
3089 }
3090
3091 bool wxWindowGTK::Show( bool show )
3092 {
3093 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3094
3095 if (!wxWindowBase::Show(show))
3096 {
3097 // nothing to do
3098 return FALSE;
3099 }
3100
3101 if (show)
3102 gtk_widget_show( m_widget );
3103 else
3104 gtk_widget_hide( m_widget );
3105
3106 return TRUE;
3107 }
3108
3109 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3110 {
3111 win->OnParentEnable(enable);
3112
3113 // Recurse, so that children have the opportunity to Do The Right Thing
3114 // and reset colours that have been messed up by a parent's (really ancestor's)
3115 // Enable call
3116 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3117 node;
3118 node = node->GetNext() )
3119 {
3120 wxWindow *child = node->GetData();
3121 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3122 wxWindowNotifyEnable(child, enable);
3123 }
3124 }
3125
3126 bool wxWindowGTK::Enable( bool enable )
3127 {
3128 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3129
3130 if (!wxWindowBase::Enable(enable))
3131 {
3132 // nothing to do
3133 return FALSE;
3134 }
3135
3136 gtk_widget_set_sensitive( m_widget, enable );
3137 if ( m_wxwindow )
3138 gtk_widget_set_sensitive( m_wxwindow, enable );
3139
3140 wxWindowNotifyEnable(this, enable);
3141
3142 return TRUE;
3143 }
3144
3145 int wxWindowGTK::GetCharHeight() const
3146 {
3147 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3148
3149 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
3150
3151 GdkFont *font = m_font.GetInternalFont( 1.0 );
3152
3153 return font->ascent + font->descent;
3154 }
3155
3156 int wxWindowGTK::GetCharWidth() const
3157 {
3158 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3159
3160 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
3161
3162 GdkFont *font = m_font.GetInternalFont( 1.0 );
3163
3164 return gdk_string_width( font, "H" );
3165 }
3166
3167 void wxWindowGTK::GetTextExtent( const wxString& string,
3168 int *x,
3169 int *y,
3170 int *descent,
3171 int *externalLeading,
3172 const wxFont *theFont ) const
3173 {
3174 wxFont fontToUse = m_font;
3175 if (theFont) fontToUse = *theFont;
3176
3177 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3178
3179 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3180 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
3181 if (y) (*y) = font->ascent + font->descent;
3182 if (descent) (*descent) = font->descent;
3183 if (externalLeading) (*externalLeading) = 0; // ??
3184 }
3185
3186 void wxWindowGTK::SetFocus()
3187 {
3188 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3189
3190 if (m_wxwindow)
3191 {
3192 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3193 {
3194 // see comment in gtk_window_focus_out_callback()
3195 gs_widgetLastFocus = m_wxwindow;
3196 gtk_widget_grab_focus (m_wxwindow);
3197 }
3198 }
3199 else if (m_widget)
3200 {
3201 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3202 {
3203 gtk_widget_grab_focus (m_widget);
3204 }
3205 else if (GTK_IS_CONTAINER(m_widget))
3206 {
3207 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3208 }
3209 else
3210 {
3211 // ?
3212 }
3213 }
3214 }
3215
3216 bool wxWindowGTK::AcceptsFocus() const
3217 {
3218 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3219 }
3220
3221 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3222 {
3223 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3224
3225 wxWindowGTK *oldParent = m_parent,
3226 *newParent = (wxWindowGTK *)newParentBase;
3227
3228 wxASSERT( GTK_IS_WIDGET(m_widget) );
3229
3230 if ( !wxWindowBase::Reparent(newParent) )
3231 return FALSE;
3232
3233 wxASSERT( GTK_IS_WIDGET(m_widget) );
3234
3235 /* prevent GTK from deleting the widget arbitrarily */
3236 gtk_widget_ref( m_widget );
3237
3238 if (oldParent)
3239 {
3240 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3241 }
3242
3243 wxASSERT( GTK_IS_WIDGET(m_widget) );
3244
3245 if (newParent)
3246 {
3247 /* insert GTK representation */
3248 (*(newParent->m_insertCallback))(newParent, this);
3249 }
3250
3251 /* reverse: prevent GTK from deleting the widget arbitrarily */
3252 gtk_widget_unref( m_widget );
3253
3254 return TRUE;
3255 }
3256
3257 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3258 {
3259 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3260
3261 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3262
3263 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3264
3265 /* add to list */
3266 AddChild( child );
3267
3268 /* insert GTK representation */
3269 (*m_insertCallback)(this, child);
3270 }
3271
3272 void wxWindowGTK::Raise()
3273 {
3274 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3275
3276 if (!m_widget->window) return;
3277
3278 gdk_window_raise( m_widget->window );
3279 }
3280
3281 void wxWindowGTK::Lower()
3282 {
3283 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3284
3285 if (!m_widget->window) return;
3286
3287 gdk_window_lower( m_widget->window );
3288 }
3289
3290 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3291 {
3292 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3293
3294 if (cursor == m_cursor)
3295 return FALSE;
3296
3297 if (g_isIdle)
3298 wxapp_install_idle_handler();
3299
3300 if (cursor == wxNullCursor)
3301 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3302 else
3303 return wxWindowBase::SetCursor( cursor );
3304 }
3305
3306 void wxWindowGTK::WarpPointer( int x, int y )
3307 {
3308 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3309
3310 /* we provide this function ourselves as it is
3311 missing in GDK (top of this file) */
3312
3313 GdkWindow *window = (GdkWindow*) NULL;
3314 if (m_wxwindow)
3315 window = GTK_PIZZA(m_wxwindow)->bin_window;
3316 else
3317 window = GetConnectWidget()->window;
3318
3319 if (window)
3320 gdk_window_warp_pointer( window, x, y );
3321 }
3322
3323 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3324 {
3325 if (!m_widget) return;
3326 if (!m_widget->window) return;
3327
3328 // temporarily hide the caret to avoid nasty interactions between caret
3329 // drawing and the window contents redraw
3330 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3331 wxCaretSuspend cs((wxWindow *)this);
3332 #endif // wxUSE_CARET
3333
3334 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3335 {
3336 if (rect)
3337 {
3338 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3339 rect->x, rect->y,
3340 rect->width, rect->height );
3341 }
3342 else
3343 {
3344 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3345 }
3346 }
3347
3348 /* there is no GTK equivalent of "draw only, don't clear" so we
3349 invent our own in the GtkPizza widget */
3350
3351 if (!rect)
3352 {
3353 if (m_wxwindow)
3354 {
3355
3356 /*
3357 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3358 gboolean old_clear = pizza->clear_on_draw;
3359 gtk_pizza_set_clear( pizza, FALSE );
3360 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3361 gtk_pizza_set_clear( pizza, old_clear );
3362 */
3363 GdkEventExpose gdk_event;
3364 gdk_event.type = GDK_EXPOSE;
3365 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3366 gdk_event.count = 0;
3367 gdk_event.area.x = 0;
3368 gdk_event.area.y = 0;
3369 gdk_event.area.width = m_wxwindow->allocation.width;
3370 gdk_event.area.height = m_wxwindow->allocation.height;
3371 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3372 }
3373 else
3374 {
3375 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3376 }
3377 }
3378 else
3379 {
3380
3381 if (m_wxwindow)
3382 {
3383 /*
3384 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3385 gboolean old_clear = pizza->clear_on_draw;
3386 gtk_pizza_set_clear( pizza, FALSE );
3387
3388 GdkRectangle gdk_rect;
3389 gdk_rect.x = rect->x;
3390 gdk_rect.y = rect->y;
3391 gdk_rect.width = rect->width;
3392 gdk_rect.height = rect->height;
3393 gtk_widget_draw( m_wxwindow, &gdk_rect );
3394 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3395
3396 gtk_pizza_set_clear( pizza, old_clear );
3397 */
3398 GdkEventExpose gdk_event;
3399 gdk_event.type = GDK_EXPOSE;
3400 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3401 gdk_event.count = 0;
3402 gdk_event.area.x = rect->x;
3403 gdk_event.area.y = rect->y;
3404 gdk_event.area.width = rect->width;
3405 gdk_event.area.height = rect->height;
3406 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
3407 }
3408 else
3409 {
3410 GdkRectangle gdk_rect;
3411 gdk_rect.x = rect->x;
3412 gdk_rect.y = rect->y;
3413 gdk_rect.width = rect->width;
3414 gdk_rect.height = rect->height;
3415 gtk_widget_draw( m_widget, &gdk_rect );
3416 }
3417 }
3418 }
3419
3420 void wxWindowGTK::Clear()
3421 {
3422 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3423
3424 if (!m_widget->window) return;
3425
3426 if (m_wxwindow && m_wxwindow->window)
3427 {
3428 // gdk_window_clear( m_wxwindow->window );
3429 }
3430 }
3431
3432 #if wxUSE_TOOLTIPS
3433 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3434 {
3435 wxWindowBase::DoSetToolTip(tip);
3436
3437 if (m_tooltip)
3438 m_tooltip->Apply( (wxWindow *)this );
3439 }
3440
3441 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3442 {
3443 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3444 }
3445 #endif // wxUSE_TOOLTIPS
3446
3447 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3448 {
3449 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3450
3451 if (!wxWindowBase::SetBackgroundColour(colour))
3452 {
3453 // don't leave if the GTK widget has just
3454 // been realized
3455 if (!m_delayedBackgroundColour) return FALSE;
3456 }
3457
3458 GdkWindow *window = (GdkWindow*) NULL;
3459 if (m_wxwindow)
3460 window = GTK_PIZZA(m_wxwindow)->bin_window;
3461 else
3462 window = GetConnectWidget()->window;
3463
3464 if (!window)
3465 {
3466 // indicate that a new style has been set
3467 // but it couldn't get applied as the
3468 // widget hasn't been realized yet.
3469 m_delayedBackgroundColour = TRUE;
3470 }
3471
3472 if ((m_wxwindow) &&
3473 (m_wxwindow->window) &&
3474 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3475 {
3476 /* wxMSW doesn't clear the window here. I don't do that either to
3477 provide compatibility. call Clear() to do the job. */
3478
3479 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3480 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3481 }
3482
3483 ApplyWidgetStyle();
3484
3485 return TRUE;
3486 }
3487
3488 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3489 {
3490 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3491
3492 if (!wxWindowBase::SetForegroundColour(colour))
3493 {
3494 // don't leave if the GTK widget has just
3495 // been realized
3496 if (!m_delayedForegroundColour) return FALSE;
3497 }
3498
3499 GdkWindow *window = (GdkWindow*) NULL;
3500 if (m_wxwindow)
3501 window = GTK_PIZZA(m_wxwindow)->bin_window;
3502 else
3503 window = GetConnectWidget()->window;
3504
3505 if (!window)
3506 {
3507 // indicate that a new style has been set
3508 // but it couldn't get applied as the
3509 // widget hasn't been realized yet.
3510 m_delayedForegroundColour = TRUE;
3511 }
3512
3513 ApplyWidgetStyle();
3514
3515 return TRUE;
3516 }
3517
3518 GtkStyle *wxWindowGTK::GetWidgetStyle()
3519 {
3520 if (m_widgetStyle)
3521 {
3522 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3523 #ifdef __WXGTK20__
3524 /* FIXME: is this necessary? */
3525 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3526 #else
3527 remake->klass = m_widgetStyle->klass;
3528 #endif
3529
3530 gtk_style_unref( m_widgetStyle );
3531 m_widgetStyle = remake;
3532 }
3533 else
3534 {
3535 GtkStyle *def = gtk_rc_get_style( m_widget );
3536
3537 if (!def)
3538 def = gtk_widget_get_default_style();
3539
3540 m_widgetStyle = gtk_style_copy( def );
3541 #ifdef __WXGTK20__
3542 /* FIXME: is this necessary? */
3543 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3544 #else
3545 m_widgetStyle->klass = def->klass;
3546 #endif
3547 }
3548
3549 return m_widgetStyle;
3550 }
3551
3552 void wxWindowGTK::SetWidgetStyle()
3553 {
3554 #if DISABLE_STYLE_IF_BROKEN_THEM
3555 if (m_widget->style->engine_data)
3556 {
3557 static bool s_warningPrinted = FALSE;
3558 if (!s_warningPrinted)
3559 {
3560 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3561 s_warningPrinted = TRUE;
3562 }
3563 m_widgetStyle = m_widget->style;
3564 return;
3565 }
3566 #endif
3567
3568 GtkStyle *style = GetWidgetStyle();
3569
3570 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3571 {
3572 gdk_font_unref( style->font );
3573 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3574 }
3575
3576 if (m_foregroundColour.Ok())
3577 {
3578 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3579 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3580 {
3581 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3582 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3583 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3584 }
3585 else
3586 {
3587 // Try to restore the gtk default style. This is still a little
3588 // oversimplified for what is probably really needed here for controls
3589 // other than buttons, but is better than not being able to (re)set a
3590 // control's foreground colour to *wxBLACK -- RL
3591 GtkStyle *def = gtk_rc_get_style( m_widget );
3592
3593 if (!def)
3594 def = gtk_widget_get_default_style();
3595
3596 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3597 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3598 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3599 }
3600 }
3601
3602 if (m_backgroundColour.Ok())
3603 {
3604 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3605 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3606 {
3607 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3608 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3609 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3610 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3611 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3612 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3613 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3614 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3615 }
3616 else
3617 {
3618 // Try to restore the gtk default style. This is still a little
3619 // oversimplified for what is probably really needed here for controls
3620 // other than buttons, but is better than not being able to (re)set a
3621 // control's background colour to default grey and means resetting a
3622 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3623 // behavior -- RL
3624 GtkStyle *def = gtk_rc_get_style( m_widget );
3625
3626 if (!def)
3627 def = gtk_widget_get_default_style();
3628
3629 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3630 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3631 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3632 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3633 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3634 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3635 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3636 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3637 }
3638 }
3639 }
3640
3641 void wxWindowGTK::ApplyWidgetStyle()
3642 {
3643 }
3644
3645 //-----------------------------------------------------------------------------
3646 // Pop-up menu stuff
3647 //-----------------------------------------------------------------------------
3648
3649 #if wxUSE_MENUS_NATIVE
3650
3651 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3652 {
3653 *is_waiting = FALSE;
3654 }
3655
3656 static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
3657 {
3658 menu->SetInvokingWindow( win );
3659 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3660 while (node)
3661 {
3662 wxMenuItem *menuitem = node->GetData();
3663 if (menuitem->IsSubMenu())
3664 {
3665 SetInvokingWindow( menuitem->GetSubMenu(), win );
3666 }
3667
3668 node = node->GetNext();
3669 }
3670 }
3671
3672 static gint gs_pop_x = 0;
3673 static gint gs_pop_y = 0;
3674
3675 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3676 gint *x, gint *y,
3677 wxWindowGTK *win )
3678 {
3679 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3680 *x = gs_pop_x;
3681 *y = gs_pop_y;
3682 }
3683
3684 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
3685 {
3686 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3687
3688 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3689
3690 SetInvokingWindow( menu, this );
3691
3692 menu->UpdateUI();
3693
3694 gs_pop_x = x;
3695 gs_pop_y = y;
3696
3697 bool is_waiting = TRUE;
3698
3699 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3700 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3701
3702 gtk_menu_popup(
3703 GTK_MENU(menu->m_menu),
3704 (GtkWidget *) NULL, // parent menu shell
3705 (GtkWidget *) NULL, // parent menu item
3706 (GtkMenuPositionFunc) pop_pos_callback,
3707 (gpointer) this, // client data
3708 0, // button used to activate it
3709 gs_timeLastClick // the time of activation
3710 );
3711
3712 while (is_waiting)
3713 {
3714 while (gtk_events_pending())
3715 gtk_main_iteration();
3716 }
3717
3718 return TRUE;
3719 }
3720
3721 #endif // wxUSE_MENUS_NATIVE
3722
3723 #if wxUSE_DRAG_AND_DROP
3724
3725 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3726 {
3727 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3728
3729 GtkWidget *dnd_widget = GetConnectWidget();
3730
3731 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3732
3733 if (m_dropTarget) delete m_dropTarget;
3734 m_dropTarget = dropTarget;
3735
3736 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3737 }
3738
3739 #endif // wxUSE_DRAG_AND_DROP
3740
3741 GtkWidget* wxWindowGTK::GetConnectWidget()
3742 {
3743 GtkWidget *connect_widget = m_widget;
3744 if (m_wxwindow) connect_widget = m_wxwindow;
3745
3746 return connect_widget;
3747 }
3748
3749 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3750 {
3751 if (m_wxwindow)
3752 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3753
3754 return (window == m_widget->window);
3755 }
3756
3757 bool wxWindowGTK::SetFont( const wxFont &font )
3758 {
3759 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3760
3761 if (!wxWindowBase::SetFont(font))
3762 {
3763 return FALSE;
3764 }
3765
3766 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3767 if ( sysbg == m_backgroundColour )
3768 {
3769 m_backgroundColour = wxNullColour;
3770 ApplyWidgetStyle();
3771 m_backgroundColour = sysbg;
3772 }
3773 else
3774 {
3775 ApplyWidgetStyle();
3776 }
3777
3778 return TRUE;
3779 }
3780
3781 void wxWindowGTK::CaptureMouse()
3782 {
3783 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3784
3785 GdkWindow *window = (GdkWindow*) NULL;
3786 if (m_wxwindow)
3787 window = GTK_PIZZA(m_wxwindow)->bin_window;
3788 else
3789 window = GetConnectWidget()->window;
3790
3791 wxCHECK_RET( window, _T("CaptureMouse() failed") );
3792
3793 wxCursor* cursor = & m_cursor;
3794 if (!cursor->Ok())
3795 cursor = wxSTANDARD_CURSOR;
3796
3797 gdk_pointer_grab( window, FALSE,
3798 (GdkEventMask)
3799 (GDK_BUTTON_PRESS_MASK |
3800 GDK_BUTTON_RELEASE_MASK |
3801 GDK_POINTER_MOTION_HINT_MASK |
3802 GDK_POINTER_MOTION_MASK),
3803 (GdkWindow *) NULL,
3804 cursor->GetCursor(),
3805 (guint32)GDK_CURRENT_TIME );
3806 g_captureWindow = this;
3807 g_captureWindowHasMouse = TRUE;
3808 }
3809
3810 void wxWindowGTK::ReleaseMouse()
3811 {
3812 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3813
3814 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3815
3816 GdkWindow *window = (GdkWindow*) NULL;
3817 if (m_wxwindow)
3818 window = GTK_PIZZA(m_wxwindow)->bin_window;
3819 else
3820 window = GetConnectWidget()->window;
3821
3822 if (!window)
3823 return;
3824
3825 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3826 g_captureWindow = (wxWindowGTK*) NULL;
3827 }
3828
3829 /* static */
3830 wxWindow *wxWindowBase::GetCapture()
3831 {
3832 return (wxWindow *)g_captureWindow;
3833 }
3834
3835 bool wxWindowGTK::IsRetained() const
3836 {
3837 return FALSE;
3838 }
3839
3840 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3841 int range, bool refresh )
3842 {
3843 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3844
3845 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3846
3847 m_hasScrolling = TRUE;
3848
3849 if (orient == wxHORIZONTAL)
3850 {
3851 float fpos = (float)pos;
3852 float frange = (float)range;
3853 float fthumb = (float)thumbVisible;
3854 if (fpos > frange-fthumb) fpos = frange-fthumb;
3855 if (fpos < 0.0) fpos = 0.0;
3856
3857 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3858 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3859 {
3860 SetScrollPos( orient, pos, refresh );
3861 return;
3862 }
3863
3864 m_oldHorizontalPos = fpos;
3865
3866 m_hAdjust->lower = 0.0;
3867 m_hAdjust->upper = frange;
3868 m_hAdjust->value = fpos;
3869 m_hAdjust->step_increment = 1.0;
3870 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3871 m_hAdjust->page_size = fthumb;
3872 }
3873 else
3874 {
3875 float fpos = (float)pos;
3876 float frange = (float)range;
3877 float fthumb = (float)thumbVisible;
3878 if (fpos > frange-fthumb) fpos = frange-fthumb;
3879 if (fpos < 0.0) fpos = 0.0;
3880
3881 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3882 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3883 {
3884 SetScrollPos( orient, pos, refresh );
3885 return;
3886 }
3887
3888 m_oldVerticalPos = fpos;
3889
3890 m_vAdjust->lower = 0.0;
3891 m_vAdjust->upper = frange;
3892 m_vAdjust->value = fpos;
3893 m_vAdjust->step_increment = 1.0;
3894 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3895 m_vAdjust->page_size = fthumb;
3896 }
3897
3898 if (orient == wxHORIZONTAL)
3899 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3900 else
3901 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3902 }
3903
3904 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3905 {
3906 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3907
3908 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3909
3910 if (orient == wxHORIZONTAL)
3911 {
3912 float fpos = (float)pos;
3913 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3914 if (fpos < 0.0) fpos = 0.0;
3915 m_oldHorizontalPos = fpos;
3916
3917 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3918 m_hAdjust->value = fpos;
3919 }
3920 else
3921 {
3922 float fpos = (float)pos;
3923 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3924 if (fpos < 0.0) fpos = 0.0;
3925 m_oldVerticalPos = fpos;
3926
3927 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3928 m_vAdjust->value = fpos;
3929 }
3930
3931 if (m_wxwindow->window)
3932 {
3933 if (orient == wxHORIZONTAL)
3934 {
3935 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3936 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3937
3938 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3939
3940 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3941 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3942 }
3943 else
3944 {
3945 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3946 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3947
3948 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3949
3950 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3951 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3952 }
3953 }
3954 }
3955
3956 int wxWindowGTK::GetScrollThumb( int orient ) const
3957 {
3958 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3959
3960 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3961
3962 if (orient == wxHORIZONTAL)
3963 return (int)(m_hAdjust->page_size+0.5);
3964 else
3965 return (int)(m_vAdjust->page_size+0.5);
3966 }
3967
3968 int wxWindowGTK::GetScrollPos( int orient ) const
3969 {
3970 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3971
3972 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3973
3974 if (orient == wxHORIZONTAL)
3975 return (int)(m_hAdjust->value+0.5);
3976 else
3977 return (int)(m_vAdjust->value+0.5);
3978 }
3979
3980 int wxWindowGTK::GetScrollRange( int orient ) const
3981 {
3982 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3983
3984 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3985
3986 if (orient == wxHORIZONTAL)
3987 return (int)(m_hAdjust->upper+0.5);
3988 else
3989 return (int)(m_vAdjust->upper+0.5);
3990 }
3991
3992 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3993 {
3994 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3995
3996 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3997
3998 if ((dx == 0) && (dy == 0)) return;
3999
4000 m_clipPaintRegion = TRUE;
4001 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4002 m_clipPaintRegion = FALSE;
4003
4004 /*
4005 if (m_children.GetCount() > 0)
4006 {
4007 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4008 }
4009 else
4010 {
4011 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
4012
4013 pizza->xoffset -= dx;
4014 pizza->yoffset -= dy;
4015
4016 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4017 gdk_gc_set_exposures( m_scrollGC, TRUE );
4018
4019 int cw = 0;
4020 int ch = 0;
4021 GetClientSize( &cw, &ch );
4022 int w = cw - abs(dx);
4023 int h = ch - abs(dy);
4024
4025 if ((h < 0) || (w < 0))
4026 {
4027 Refresh();
4028 }
4029 else
4030 {
4031 int s_x = 0;
4032 int s_y = 0;
4033 if (dx < 0) s_x = -dx;
4034 if (dy < 0) s_y = -dy;
4035 int d_x = 0;
4036 int d_y = 0;
4037 if (dx > 0) d_x = dx;
4038 if (dy > 0) d_y = dy;
4039
4040 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4041 pizza->bin_window, s_x, s_y, w, h );
4042
4043 wxRect rect;
4044 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4045 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4046 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4047 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4048
4049 Refresh( TRUE, &rect );
4050 }
4051
4052 gdk_gc_unref( m_scrollGC );
4053 }
4054 */
4055 }
4056
4057 // Find the wxWindow at the current mouse position, also returning the mouse
4058 // position.
4059 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4060 {
4061 pt = wxGetMousePosition();
4062 wxWindow* found = wxFindWindowAtPoint(pt);
4063 return found;
4064 }
4065
4066 // Get the current mouse position.
4067 wxPoint wxGetMousePosition()
4068 {
4069 /* This crashes when used within wxHelpContext,
4070 so we have to use the X-specific implementation below.
4071 gint x, y;
4072 GdkModifierType *mask;
4073 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4074
4075 return wxPoint(x, y);
4076 */
4077
4078 int x, y;
4079 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4080 if (!windowAtPtr)
4081 return wxPoint(-999, -999);
4082
4083 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4084 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4085 Window rootReturn, childReturn;
4086 int rootX, rootY, winX, winY;
4087 unsigned int maskReturn;
4088
4089 XQueryPointer (display,
4090 rootWindow,
4091 &rootReturn,
4092 &childReturn,
4093 &rootX, &rootY, &winX, &winY, &maskReturn);
4094 return wxPoint(rootX, rootY);
4095
4096 }
4097