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