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