]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/minifram.cpp
Fixed premature exit of helpview sample and utility
[wxWidgets.git] / src / gtk / minifram.cpp
CommitLineData
b2b3ccc5 1/////////////////////////////////////////////////////////////////////////////
340bfb43 2// Name: src/gtk/minifram.cpp
b2b3ccc5
RR
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
b2b3ccc5
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
dcf924a3
RR
13#if wxUSE_MINIFRAME
14
11dbb4bf
WS
15#include "wx/minifram.h"
16
17#ifndef WX_PRECOMP
b41b2a05 18 #include "wx/settings.h"
0416c418
PC
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
11dbb4bf 21#endif
b2b3ccc5 22
83624f79 23#include "wx/gtk/win_gtk.h"
fab591c5 24#include "wx/gtk/private.h"
83624f79 25
32a95f9f
RR
26//-----------------------------------------------------------------------------
27// data
28//-----------------------------------------------------------------------------
29
8480b297
RR
30extern bool g_blockEventsOnDrag;
31extern bool g_blockEventsOnScroll;
c2fa61e8 32extern GtkWidget *wxGetRootWindow();
32a95f9f 33
32a95f9f
RR
34//-----------------------------------------------------------------------------
35// "expose_event" of m_mainWidget
36//-----------------------------------------------------------------------------
37
6d976005
RR
38// StepColour() it a utility function that simply darkens
39// or lightens a color, based on the specified percentage
40static 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
48static 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
865bb325 60extern "C" {
6d727f6c 61static gboolean gtk_window_own_expose_callback(GtkWidget* widget, GdkEventExpose* gdk_event, wxMiniFrame* win)
32a95f9f 62{
14819684 63 // don't need to install idle handler, its done from "event" signal
acfd422a 64
6d727f6c
PC
65 if (!win->m_hasVMT || gdk_event->count > 0)
66 return false;
c2fa61e8 67
da048e3d 68 GtkPizza *pizza = GTK_PIZZA(widget);
c2fa61e8 69
67b73b9a
MR
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);
b9a535f5 77
00e4ffbc 78 int style = win->GetWindowStyle();
b41b2a05 79
85a0a12a
RR
80 wxClientDC dc(win);
81 // Hack alert
82 dc.m_window = pizza->bin_window;
b41b2a05 83
85a0a12a
RR
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
340bfb43 91 if (!win->GetTitle().empty() &&
00e4ffbc
RR
92 ((style & wxCAPTION) ||
93 (style & wxTINY_CAPTION_HORIZ) ||
94 (style & wxTINY_CAPTION_VERT)))
b9a535f5 95 {
ba718523
RR
96 dc.SetFont( *wxSMALL_FONT );
97 int height = dc.GetCharHeight();
340bfb43 98
6d976005
RR
99 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
100 dc.SetBrush( brush );
101 dc.SetPen( *wxTRANSPARENT_PEN );
1ed6bbc2 102 dc.DrawRectangle( 3, 3, win->m_width - 7, height );
ba718523 103
ba718523
RR
104 dc.SetTextForeground( *wxWHITE );
105 dc.DrawText( win->GetTitle(), 6, 3 );
00e4ffbc
RR
106
107 if (style & wxCLOSE_BOX)
ba6ce5fb 108 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 2, true );
b9a535f5 109 }
6d727f6c 110 return false;
32a95f9f 111}
865bb325 112}
32a95f9f 113
32a95f9f
RR
114//-----------------------------------------------------------------------------
115// "button_press_event" of m_mainWidget
116//-----------------------------------------------------------------------------
117
865bb325 118extern "C" {
32a95f9f
RR
119static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
120{
14819684 121 // don't need to install idle handler, its done from "event" signal
acfd422a 122
a2053b27 123 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
124 if (g_blockEventsOnDrag) return TRUE;
125 if (g_blockEventsOnScroll) return TRUE;
126
127 if (win->m_isDragging) return TRUE;
128
2c990ec0
RR
129 GtkPizza *pizza = GTK_PIZZA(widget);
130 if (gdk_event->window != pizza->bin_window) return TRUE;
ba718523 131
85a0a12a
RR
132 int style = win->GetWindowStyle();
133
00e4ffbc
RR
134 int y = (int)gdk_event->y;
135 int x = (int)gdk_event->x;
b41b2a05 136
85a0a12a
RR
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);
b41b2a05 154
85a0a12a
RR
155 return TRUE;
156 }
00e4ffbc 157
00e4ffbc
RR
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 }
b41b2a05 167
ba718523
RR
168 wxClientDC dc(win);
169 dc.SetFont( *wxSMALL_FONT );
170 int height = dc.GetCharHeight() + 1;
340bfb43 171
00e4ffbc
RR
172
173 if (y > height) return TRUE;
340bfb43 174
4dcaf11a 175 gdk_window_raise( win->m_widget->window );
c2fa61e8 176
32a95f9f
RR
177 gdk_pointer_grab( widget->window, FALSE,
178 (GdkEventMask)
179 (GDK_BUTTON_PRESS_MASK |
180 GDK_BUTTON_RELEASE_MASK |
f03fc89f 181 GDK_POINTER_MOTION_MASK |
32a95f9f 182 GDK_POINTER_MOTION_HINT_MASK |
f03fc89f 183 GDK_BUTTON_MOTION_MASK |
32a95f9f
RR
184 GDK_BUTTON1_MOTION_MASK),
185 (GdkWindow *) NULL,
186 (GdkCursor *) NULL,
7941ba11 187 (unsigned int) GDK_CURRENT_TIME );
c2fa61e8 188
00e4ffbc
RR
189 win->m_diffX = x;
190 win->m_diffY = y;
32a95f9f
RR
191 win->m_oldX = 0;
192 win->m_oldY = 0;
c2fa61e8 193
340bfb43 194 win->m_isDragging = true;
32a95f9f
RR
195
196 return TRUE;
197}
865bb325 198}
32a95f9f
RR
199
200//-----------------------------------------------------------------------------
201// "button_release_event" of m_mainWidget
202//-----------------------------------------------------------------------------
203
865bb325 204extern "C" {
32a95f9f
RR
205static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
206{
14819684 207 // don't need to install idle handler, its done from "event" signal
acfd422a 208
a2053b27 209 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
210 if (g_blockEventsOnDrag) return TRUE;
211 if (g_blockEventsOnScroll) return TRUE;
212
213 if (!win->m_isDragging) return TRUE;
c2fa61e8 214
11dbb4bf 215 win->m_isDragging = false;
c2fa61e8 216
32a95f9f
RR
217 int x = (int)gdk_event->x;
218 int y = (int)gdk_event->y;
c2fa61e8 219
13111b2a 220 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
c2fa61e8 221 int org_x = 0;
32a95f9f
RR
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;
121a3581
RR
226 win->m_x = x;
227 win->m_y = y;
9adb9063 228 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
32a95f9f
RR
229
230 return TRUE;
231}
865bb325 232}
32a95f9f 233
85a0a12a
RR
234//-----------------------------------------------------------------------------
235// "leave_notify_event" of m_mainWidget
236//-----------------------------------------------------------------------------
237
238extern "C" {
239static gboolean
240gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
241{
14819684 242 // don't need to install idle handler, its done from "event" signal
85a0a12a
RR
243
244 if (!win->m_hasVMT) return FALSE;
245 if (g_blockEventsOnDrag) return FALSE;
246
247 gdk_window_set_cursor( widget->window, NULL );
b41b2a05 248
85a0a12a
RR
249 return FALSE;
250}
251}
252
32a95f9f
RR
253//-----------------------------------------------------------------------------
254// "motion_notify_event" of m_mainWidget
255//-----------------------------------------------------------------------------
256
865bb325 257extern "C" {
b41b2a05 258static gint
85a0a12a 259gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
32a95f9f 260{
14819684 261 // don't need to install idle handler, its done from "event" signal
acfd422a 262
a2053b27 263 if (!win->m_hasVMT) return FALSE;
32a95f9f
RR
264 if (g_blockEventsOnDrag) return TRUE;
265 if (g_blockEventsOnScroll) return TRUE;
266
32a95f9f
RR
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
85a0a12a 278 int style = win->GetWindowStyle();
b41b2a05 279
d02d8b4c
RR
280 int x = (int)gdk_event->x;
281 int y = (int)gdk_event->y;
b41b2a05 282
85a0a12a
RR
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 }
b41b2a05 294
85a0a12a
RR
295 win->m_oldX = x - win->m_diffX;
296 win->m_oldY = y - win->m_diffY;
297
d02d8b4c
RR
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
c2fa61e8 307
32a95f9f
RR
308 return TRUE;
309}
865bb325 310}
32a95f9f 311
b2b3ccc5
RR
312//-----------------------------------------------------------------------------
313// wxMiniFrame
314//-----------------------------------------------------------------------------
315
00e4ffbc
RR
316static 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
5d5b3a40 321
b2b3ccc5
RR
322IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
323
324bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
325 const wxPoint &pos, const wxSize &size,
326 long style, const wxString &name )
327{
2c990ec0 328 style = style | wxCAPTION;
b9a535f5
RR
329
330 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
00e4ffbc 331 m_miniTitle = 16;
c2fa61e8 332
6d976005 333 if (style & wxRESIZE_BORDER)
85a0a12a 334 m_miniEdge = 4;
6d976005
RR
335 else
336 m_miniEdge = 3;
340bfb43 337 m_isDragging = false;
b2b3ccc5
RR
338 m_oldX = -1;
339 m_oldY = -1;
340 m_diffX = 0;
341 m_diffY = 0;
c2fa61e8 342
b2b3ccc5
RR
343 wxFrame::Create( parent, id, title, pos, size, style, name );
344
2c990ec0
RR
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 }
340bfb43 349
00e4ffbc 350 if ((style & wxCLOSE_BOX) &&
b9a535f5
RR
351 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
352 {
00e4ffbc 353 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
c4d39711 354 img.Replace(0,0,0,123,123,123);
00e4ffbc
RR
355 img.SetMaskColour(123,123,123);
356 m_closeButton = wxBitmap( img );
b9a535f5 357 }
c2fa61e8 358
32a95f9f 359 /* these are called when the borders are drawn */
9fa72bd2
MR
360 g_signal_connect (m_mainWidget, "expose_event",
361 G_CALLBACK (gtk_window_own_expose_callback), this );
b2b3ccc5 362
32a95f9f 363 /* these are required for dragging the mini frame around */
9fa72bd2
MR
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);
85a0a12a
RR
370 g_signal_connect (m_mainWidget, "leave_notify_event",
371 G_CALLBACK (gtk_window_leave_callback), this);
340bfb43 372 return true;
b2b3ccc5 373}
dcf924a3 374
400be137
RR
375void wxMiniFrame::SetTitle( const wxString &title )
376{
377 wxFrame::SetTitle( title );
340bfb43 378
c67e060d
RR
379 if (GTK_PIZZA(m_mainWidget)->bin_window)
380 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
400be137
RR
381}
382
11dbb4bf 383#endif // wxUSE_MINIFRAME