expose handlers are supposed to return a gboolean;
[wxWidgets.git] / src / gtk / minifram.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MINIFRAME
14
15 #include "wx/minifram.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/gtk/win_gtk.h"
24 #include "wx/gtk/private.h"
25
26 //-----------------------------------------------------------------------------
27 // data
28 //-----------------------------------------------------------------------------
29
30 extern bool g_blockEventsOnDrag;
31 extern bool g_blockEventsOnScroll;
32 extern GtkWidget *wxGetRootWindow();
33
34 //-----------------------------------------------------------------------------
35 // "expose_event" of m_mainWidget
36 //-----------------------------------------------------------------------------
37
38 // StepColour() it a utility function that simply darkens
39 // or lightens a color, based on the specified percentage
40 static wxColor StepColour(const wxColor& c, int percent)
41 {
42 int r = c.Red(), g = c.Green(), b = c.Blue();
43 return wxColour((unsigned char)wxMin((r*percent)/100,255),
44 (unsigned char)wxMin((g*percent)/100,255),
45 (unsigned char)wxMin((b*percent)/100,255));
46 }
47
48 static wxColor LightContrastColour(const wxColour& c)
49 {
50 int amount = 120;
51
52 // if the color is especially dark, then
53 // make the contrast even lighter
54 if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
55 amount = 160;
56
57 return StepColour(c, amount);
58 }
59
60 extern "C" {
61 static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
62 {
63 // don't need to install idle handler, its done from "event" signal
64
65 if (!win->m_hasVMT || gdk_event->count > 0)
66 return false;
67
68 GtkPizza *pizza = GTK_PIZZA(widget);
69
70 gtk_paint_shadow (widget->style,
71 pizza->bin_window,
72 GTK_STATE_NORMAL,
73 GTK_SHADOW_OUT,
74 NULL, NULL, NULL, // FIXME: No clipping?
75 0, 0,
76 win->m_width, win->m_height);
77
78 int style = win->GetWindowStyle();
79
80 wxClientDC dc(win);
81 // Hack alert
82 dc.m_window = pizza->bin_window;
83
84 if (style & wxRESIZE_BORDER)
85 {
86 dc.SetBrush( *wxGREY_BRUSH );
87 dc.SetPen( *wxTRANSPARENT_PEN );
88 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
89 }
90
91 if (!win->GetTitle().empty() &&
92 ((style & wxCAPTION) ||
93 (style & wxTINY_CAPTION_HORIZ) ||
94 (style & wxTINY_CAPTION_VERT)))
95 {
96 dc.SetFont( *wxSMALL_FONT );
97 int height = dc.GetCharHeight();
98
99 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
100 dc.SetBrush( brush );
101 dc.SetPen( *wxTRANSPARENT_PEN );
102 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
103
104 dc.SetTextForeground( *wxWHITE );
105 dc.DrawText( win->GetTitle(), 6, 3 );
106
107 if (style & wxCLOSE_BOX)
108 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
109 }
110 return false;
111 }
112 }
113
114 //-----------------------------------------------------------------------------
115 // "button_press_event" of m_mainWidget
116 //-----------------------------------------------------------------------------
117
118 extern "C" {
119 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
120 {
121 // don't need to install idle handler, its done from "event" signal
122
123 if (!win->m_hasVMT) return FALSE;
124 if (g_blockEventsOnDrag) return TRUE;
125 if (g_blockEventsOnScroll) return TRUE;
126
127 if (win->m_isDragging) return TRUE;
128
129 GtkPizza *pizza = GTK_PIZZA(widget);
130 if (gdk_event->window != pizza->bin_window) return TRUE;
131
132 int style = win->GetWindowStyle();
133
134 int y = (int)gdk_event->y;
135 int x = (int)gdk_event->x;
136
137 if ((style & wxRESIZE_BORDER) &&
138 (x > win->m_width-14) && (y > win->m_height-14))
139 {
140 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
141
142 GdkWindow *source = GTK_PIZZA(widget)->bin_window;
143
144 int org_x = 0;
145 int org_y = 0;
146 gdk_window_get_origin( source, &org_x, &org_y );
147
148 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
149 GDK_WINDOW_EDGE_SOUTH_EAST,
150 1,
151 org_x + x,
152 org_y + y,
153 0);
154
155 return TRUE;
156 }
157
158 if ((style & wxCLOSE_BOX) &&
159 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
160 {
161 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
162 {
163 win->Close();
164 return TRUE;
165 }
166 }
167
168 wxClientDC dc(win);
169 dc.SetFont( *wxSMALL_FONT );
170 int height = dc.GetCharHeight() + 1;
171
172
173 if (y > height) return TRUE;
174
175 gdk_window_raise( win->m_widget->window );
176
177 gdk_pointer_grab( widget->window, FALSE,
178 (GdkEventMask)
179 (GDK_BUTTON_PRESS_MASK |
180 GDK_BUTTON_RELEASE_MASK |
181 GDK_POINTER_MOTION_MASK |
182 GDK_POINTER_MOTION_HINT_MASK |
183 GDK_BUTTON_MOTION_MASK |
184 GDK_BUTTON1_MOTION_MASK),
185 (GdkWindow *) NULL,
186 (GdkCursor *) NULL,
187 (unsigned int) GDK_CURRENT_TIME );
188
189 win->m_diffX = x;
190 win->m_diffY = y;
191 win->m_oldX = 0;
192 win->m_oldY = 0;
193
194 win->m_isDragging = true;
195
196 return TRUE;
197 }
198 }
199
200 //-----------------------------------------------------------------------------
201 // "button_release_event" of m_mainWidget
202 //-----------------------------------------------------------------------------
203
204 extern "C" {
205 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
206 {
207 // don't need to install idle handler, its done from "event" signal
208
209 if (!win->m_hasVMT) return FALSE;
210 if (g_blockEventsOnDrag) return TRUE;
211 if (g_blockEventsOnScroll) return TRUE;
212
213 if (!win->m_isDragging) return TRUE;
214
215 win->m_isDragging = false;
216
217 int x = (int)gdk_event->x;
218 int y = (int)gdk_event->y;
219
220 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
221 int org_x = 0;
222 int org_y = 0;
223 gdk_window_get_origin( widget->window, &org_x, &org_y );
224 x += org_x - win->m_diffX;
225 y += org_y - win->m_diffY;
226 win->m_x = x;
227 win->m_y = y;
228 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
229
230 return TRUE;
231 }
232 }
233
234 //-----------------------------------------------------------------------------
235 // "leave_notify_event" of m_mainWidget
236 //-----------------------------------------------------------------------------
237
238 extern "C" {
239 static gboolean
240 gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
241 {
242 // don't need to install idle handler, its done from "event" signal
243
244 if (!win->m_hasVMT) return FALSE;
245 if (g_blockEventsOnDrag) return FALSE;
246
247 gdk_window_set_cursor( widget->window, NULL );
248
249 return FALSE;
250 }
251 }
252
253 //-----------------------------------------------------------------------------
254 // "motion_notify_event" of m_mainWidget
255 //-----------------------------------------------------------------------------
256
257 extern "C" {
258 static gint
259 gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
260 {
261 // don't need to install idle handler, its done from "event" signal
262
263 if (!win->m_hasVMT) return FALSE;
264 if (g_blockEventsOnDrag) return TRUE;
265 if (g_blockEventsOnScroll) return TRUE;
266
267 if (gdk_event->is_hint)
268 {
269 int x = 0;
270 int y = 0;
271 GdkModifierType state;
272 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
273 gdk_event->x = x;
274 gdk_event->y = y;
275 gdk_event->state = state;
276 }
277
278 int style = win->GetWindowStyle();
279
280 int x = (int)gdk_event->x;
281 int y = (int)gdk_event->y;
282
283 if (!win->m_isDragging)
284 {
285 if (style & wxRESIZE_BORDER)
286 {
287 if ((x > win->m_width-14) && (y > win->m_height-14))
288 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
289 else
290 gdk_window_set_cursor( widget->window, NULL );
291 }
292 return TRUE;
293 }
294
295 win->m_oldX = x - win->m_diffX;
296 win->m_oldY = y - win->m_diffY;
297
298 int org_x = 0;
299 int org_y = 0;
300 gdk_window_get_origin( widget->window, &org_x, &org_y );
301 x += org_x - win->m_diffX;
302 y += org_y - win->m_diffY;
303 win->m_x = x;
304 win->m_y = y;
305 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
306
307
308 return TRUE;
309 }
310 }
311
312 //-----------------------------------------------------------------------------
313 // wxMiniFrame
314 //-----------------------------------------------------------------------------
315
316 static unsigned char close_bits[]={
317 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
318 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
319 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
320
321
322 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
323
324 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
325 const wxPoint &pos, const wxSize &size,
326 long style, const wxString &name )
327 {
328 style = style | wxCAPTION;
329
330 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
331 m_miniTitle = 16;
332
333 if (style & wxRESIZE_BORDER)
334 m_miniEdge = 4;
335 else
336 m_miniEdge = 3;
337 m_isDragging = false;
338 m_oldX = -1;
339 m_oldY = -1;
340 m_diffX = 0;
341 m_diffY = 0;
342
343 wxFrame::Create( parent, id, title, pos, size, style, name );
344
345 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
346 {
347 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
348 }
349
350 if ((style & wxCLOSE_BOX) &&
351 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
352 {
353 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
354 img.Replace(0,0,0,123,123,123);
355 img.SetMaskColour(123,123,123);
356 m_closeButton = wxBitmap( img );
357 }
358
359 /* these are called when the borders are drawn */
360 g_signal_connect (m_mainWidget, "expose_event",
361 G_CALLBACK (gtk_window_own_expose_callback), this );
362
363 /* these are required for dragging the mini frame around */
364 g_signal_connect (m_mainWidget, "button_press_event",
365 G_CALLBACK (gtk_window_button_press_callback), this);
366 g_signal_connect (m_mainWidget, "button_release_event",
367 G_CALLBACK (gtk_window_button_release_callback), this);
368 g_signal_connect (m_mainWidget, "motion_notify_event",
369 G_CALLBACK (gtk_window_motion_notify_callback), this);
370 g_signal_connect (m_mainWidget, "leave_notify_event",
371 G_CALLBACK (gtk_window_leave_callback), this);
372 return true;
373 }
374
375 void wxMiniFrame::SetTitle( const wxString &title )
376 {
377 wxFrame::SetTitle( title );
378
379 if (GTK_PIZZA(m_mainWidget)->bin_window)
380 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
381 }
382
383 #endif // wxUSE_MINIFRAME