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