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