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