1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/minifram.h"
18 #include "wx/settings.h"
19 #include "wx/dcscreen.h"
23 #include "wx/gtk/win_gtk.h"
24 #include "wx/gtk/private.h"
27 #include <gdk/gdkprivate.h>
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 extern bool g_blockEventsOnDrag
;
35 extern bool g_blockEventsOnScroll
;
36 extern GtkWidget
*wxGetRootWindow();
38 //-----------------------------------------------------------------------------
39 // "expose_event" of m_mainWidget
40 //-----------------------------------------------------------------------------
42 // StepColour() it a utility function that simply darkens
43 // or lightens a color, based on the specified percentage
44 static wxColor
StepColour(const wxColor
& c
, int percent
)
46 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
47 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
48 (unsigned char)wxMin((g
*percent
)/100,255),
49 (unsigned char)wxMin((b
*percent
)/100,255));
52 static wxColor
LightContrastColour(const wxColour
& c
)
56 // if the color is especially dark, then
57 // make the contrast even lighter
58 if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128)
61 return StepColour(c
, amount
);
65 static void gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxMiniFrame
*win
)
67 // don't need to install idle handler, its done from "event" signal
69 if (!win
->m_hasVMT
) return;
70 if (gdk_event
->count
> 0) return;
72 GtkPizza
*pizza
= GTK_PIZZA(widget
);
74 gtk_paint_shadow (widget
->style
,
78 NULL
, NULL
, NULL
, // FIXME: No clipping?
80 win
->m_width
, win
->m_height
);
82 int style
= win
->GetWindowStyle();
86 dc
.m_window
= pizza
->bin_window
;
88 if (style
& wxRESIZE_BORDER
)
90 dc
.SetBrush( *wxGREY_BRUSH
);
91 dc
.SetPen( *wxTRANSPARENT_PEN
);
92 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
95 if (!win
->GetTitle().empty() &&
96 ((style
& wxCAPTION
) ||
97 (style
& wxTINY_CAPTION_HORIZ
) ||
98 (style
& wxTINY_CAPTION_VERT
)))
100 dc
.SetFont( *wxSMALL_FONT
);
101 int height
= dc
.GetCharHeight();
103 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
104 dc
.SetBrush( brush
);
105 dc
.SetPen( *wxTRANSPARENT_PEN
);
106 dc
.DrawRectangle( 3, 3, win
->m_width
- 7, height
-2 );
108 dc
.SetTextForeground( *wxWHITE
);
109 dc
.DrawText( win
->GetTitle(), 6, 3 );
111 if (style
& wxCLOSE_BOX
)
112 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-19, 3, true );
117 //-----------------------------------------------------------------------------
118 // "button_press_event" of m_mainWidget
119 //-----------------------------------------------------------------------------
122 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
124 // don't need to install idle handler, its done from "event" signal
126 if (!win
->m_hasVMT
) return FALSE
;
127 if (g_blockEventsOnDrag
) return TRUE
;
128 if (g_blockEventsOnScroll
) return TRUE
;
130 if (win
->m_isDragging
) return TRUE
;
132 GtkPizza
*pizza
= GTK_PIZZA(widget
);
133 if (gdk_event
->window
!= pizza
->bin_window
) return TRUE
;
135 int style
= win
->GetWindowStyle();
137 int y
= (int)gdk_event
->y
;
138 int x
= (int)gdk_event
->x
;
140 if ((style
& wxRESIZE_BORDER
) &&
141 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
143 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
145 GdkWindow
*source
= GTK_PIZZA(widget
)->bin_window
;
149 gdk_window_get_origin( source
, &org_x
, &org_y
);
151 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
152 GDK_WINDOW_EDGE_SOUTH_EAST
,
161 if ((style
& wxCLOSE_BOX
) &&
162 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
164 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
172 dc
.SetFont( *wxSMALL_FONT
);
173 int height
= dc
.GetCharHeight() + 1;
176 if (y
> height
) return TRUE
;
178 gdk_window_raise( win
->m_widget
->window
);
180 gdk_pointer_grab( widget
->window
, FALSE
,
182 (GDK_BUTTON_PRESS_MASK
|
183 GDK_BUTTON_RELEASE_MASK
|
184 GDK_POINTER_MOTION_MASK
|
185 GDK_POINTER_MOTION_HINT_MASK
|
186 GDK_BUTTON_MOTION_MASK
|
187 GDK_BUTTON1_MOTION_MASK
),
190 (unsigned int) GDK_CURRENT_TIME
);
197 win
->m_isDragging
= true;
203 //-----------------------------------------------------------------------------
204 // "button_release_event" of m_mainWidget
205 //-----------------------------------------------------------------------------
208 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxMiniFrame
*win
)
210 // don't need to install idle handler, its done from "event" signal
212 if (!win
->m_hasVMT
) return FALSE
;
213 if (g_blockEventsOnDrag
) return TRUE
;
214 if (g_blockEventsOnScroll
) return TRUE
;
216 if (!win
->m_isDragging
) return TRUE
;
218 win
->m_isDragging
= false;
220 int x
= (int)gdk_event
->x
;
221 int y
= (int)gdk_event
->y
;
223 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
226 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
227 x
+= org_x
- win
->m_diffX
;
228 y
+= org_y
- win
->m_diffY
;
231 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
237 //-----------------------------------------------------------------------------
238 // "leave_notify_event" of m_mainWidget
239 //-----------------------------------------------------------------------------
243 gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxMiniFrame
*win
)
245 // don't need to install idle handler, its done from "event" signal
247 if (!win
->m_hasVMT
) return FALSE
;
248 if (g_blockEventsOnDrag
) return FALSE
;
250 gdk_window_set_cursor( widget
->window
, NULL
);
256 //-----------------------------------------------------------------------------
257 // "motion_notify_event" of m_mainWidget
258 //-----------------------------------------------------------------------------
262 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
264 // don't need to install idle handler, its done from "event" signal
266 if (!win
->m_hasVMT
) return FALSE
;
267 if (g_blockEventsOnDrag
) return TRUE
;
268 if (g_blockEventsOnScroll
) return TRUE
;
270 if (gdk_event
->is_hint
)
274 GdkModifierType state
;
275 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
278 gdk_event
->state
= state
;
281 int style
= win
->GetWindowStyle();
283 int x
= (int)gdk_event
->x
;
284 int y
= (int)gdk_event
->y
;
286 if (!win
->m_isDragging
)
288 if (style
& wxRESIZE_BORDER
)
290 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
291 gdk_window_set_cursor( widget
->window
, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER
) );
293 gdk_window_set_cursor( widget
->window
, NULL
);
298 win
->m_oldX
= x
- win
->m_diffX
;
299 win
->m_oldY
= y
- win
->m_diffY
;
303 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
304 x
+= org_x
- win
->m_diffX
;
305 y
+= org_y
- win
->m_diffY
;
308 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
315 //-----------------------------------------------------------------------------
317 //-----------------------------------------------------------------------------
319 static unsigned char close_bits
[]={
320 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
321 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
322 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
325 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
327 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
328 const wxPoint
&pos
, const wxSize
&size
,
329 long style
, const wxString
&name
)
331 style
= style
| wxCAPTION
;
333 if ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
))
336 if (style
& wxRESIZE_BORDER
)
340 m_isDragging
= false;
346 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
348 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
350 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
353 if ((style
& wxCLOSE_BOX
) &&
354 ((style
& wxCAPTION
) || (style
& wxTINY_CAPTION_HORIZ
) || (style
& wxTINY_CAPTION_VERT
)))
356 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
357 img
.Replace(0,0,0,123,123,123);
358 img
.SetMaskColour(123,123,123);
359 m_closeButton
= wxBitmap( img
);
362 /* these are called when the borders are drawn */
363 g_signal_connect (m_mainWidget
, "expose_event",
364 G_CALLBACK (gtk_window_own_expose_callback
), this );
366 /* these are required for dragging the mini frame around */
367 g_signal_connect (m_mainWidget
, "button_press_event",
368 G_CALLBACK (gtk_window_button_press_callback
), this);
369 g_signal_connect (m_mainWidget
, "button_release_event",
370 G_CALLBACK (gtk_window_button_release_callback
), this);
371 g_signal_connect (m_mainWidget
, "motion_notify_event",
372 G_CALLBACK (gtk_window_motion_notify_callback
), this);
373 g_signal_connect (m_mainWidget
, "leave_notify_event",
374 G_CALLBACK (gtk_window_leave_callback
), this);
378 void wxMiniFrame::SetTitle( const wxString
&title
)
380 wxFrame::SetTitle( title
);
382 if (GTK_PIZZA(m_mainWidget
)->bin_window
)
383 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget
)->bin_window
, NULL
, true );
386 #endif // wxUSE_MINIFRAME