#include #ifdef GUI_GTK namespace Upp { #define LLOG(x) // DLOG(x) void TopWindow::SyncSizeHints() { GuiLock __; if(!top) return; Size sz0 = GetRect().GetSize(); LLOG("SyncSizeHints sz0: " << sz0 << ", sizeable: " << sizeable << ", min: " << GetMinSize() << ", max: " << GetMaxSize()); Top *top = GetTop(); if(top) { int mcx = 0; int mcy = 0; if(top->csd) { mcx += csd_border.left + csd_border.right; mcy += csd_border.top + csd_border.bottom; if(custom_bar_frame) mcy += GetCustomTitleBarMetrics().height; else mcy += csd_std_header_cy; } GdkGeometry m; m.base_width = sz0.cx; m.base_height = sz0.cy; Size minsz = sizeable ? GetMinSize() : sz0; m.min_width = LSCH(minsz.cx + mcx); m.min_height = LSCH(minsz.cy + mcy); Size maxsz = sizeable ? GetMaxSize() : sz0; m.max_width = LSCH(maxsz.cx + mcx); m.max_height = LSCH(maxsz.cy + mcy); gtk_window_set_resizable(gtk(), sizeable); gtk_window_set_geometry_hints(gtk(), NULL, &m, GdkWindowHints(GDK_HINT_MIN_SIZE|GDK_HINT_MAX_SIZE|GDK_HINT_BASE_SIZE)); gtk_widget_set_size_request(top->window, m.min_width, m.min_height); } SyncCustomBar(); } void TopWindow::SyncTitle() { GuiLock __; if(GetTop()) gtk_window_set_title(gtk(), FromUnicode(title, CHARSET_UTF8)); } void TopWindow::SyncCaption() { GuiLock __; SyncTitle(); if(top) { GList *icons = NULL; if(gdk_icon.Set(icon)) icons = g_list_append(icons, gdk_icon); if(gdk_largeicon.Set(largeicon)) icons = g_list_append(icons, gdk_largeicon); if(icons != NULL) { gtk_window_set_icon_list(gtk(), icons); g_list_free(icons); } gtk_window_set_decorated(gtk(), !frameless); gtk_window_set_urgency_hint(gtk(), urgent); } } void TopWindow::CenterRect(Ctrl *owner) { GuiLock __; SetupRect(owner); if(owner && center == 1 || center == 2) { Size sz = GetRect().Size(); Rect wr = owner ? owner->GetWorkArea() : Ctrl::GetPrimaryWorkArea(); Rect fm = frameMargins; Rect r = (center == 1 && owner ? owner->GetRect() : wr) .CenterRect(sz); wr.left += fm.left; wr.right -= fm.right; wr.top += fm.top; wr.bottom -= fm.bottom; if(r.top < wr.top) { r.top = wr.top; r.bottom = r.top + sz.cy; } if(r.left < wr.left) { r.left = wr.left; r.right = r.left + sz.cx; } if(r.bottom > wr.bottom) { r.bottom = wr.bottom; r.top = r.bottom - sz.cy; } if(r.right > wr.right) { r.right = wr.right; r.left = r.right - sz.cx; } minsize.cx = min(minsize.cx, r.GetWidth()); minsize.cy = min(minsize.cy, r.GetHeight()); SetRect(r); } } gboolean TopWindow::StateEvent(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data) { TopWindow *w = (TopWindow *)user_data; dword h = event->new_window_state; int prev = w->state; if(h & GDK_WINDOW_STATE_FULLSCREEN) w->state = FULLSCREEN; else if(h & GDK_WINDOW_STATE_ICONIFIED) w->state = MINIMIZED; else if(h & GDK_WINDOW_STATE_MAXIMIZED) w->state = MAXIMIZED; else { w->state = OVERLAPPED; w->overlapped = w->GetRect(); } LLOG("StateEvent " << prev << " -> " << (int)w->state); w->topmost = h & GDK_WINDOW_STATE_ABOVE; w->Layout(); if(prev == MINIMIZED && w->state != MINIMIZED) { prev_mouse_pos = CurrentMousePos = Null; // we lost the track of mouse, otherwise "minimize" button would render highlighted if(w->custom_bar_icons) w->custom_bar_icons->RefreshFrame(); } return FALSE; } void TopWindow::Open(Ctrl *owner) { GuiLock __; LLOG("OPEN " << Name() << " owner: " << UPP::Name(owner)); if(dokeys && (!GUI_AKD_Conservative() || GetAccessKeysDeep() <= 1)) DistributeAccessKeys(); if(fullscreen) SetRect(GetPrimaryScreenArea()); else CenterRect(owner); IgnoreMouseUp(); Create(owner, false); Top *top = GetTop(); if(top) g_signal_connect(top->window, "window-state-event", G_CALLBACK(StateEvent), this); SyncSizeHints(); SyncCaption(); PlaceFocus(); int q = state; state = OVERLAPPED; SetMode(q); SyncTopMost(); } void TopWindow::Open() { Open(GetActiveWindow()); } void TopWindow::OpenMain() { Open(NULL); } void TopWindow::SyncTopMost() { GuiLock __; if(top) gtk_window_set_keep_above(gtk(), topmost); } void TopWindow::SetMode(int mode) { GuiLock __; GtkWindow *w = gtk(); if(w) switch(state) { case MINIMIZED: fullscreen = false; gtk_window_iconify(w); break; case MAXIMIZED: fullscreen = false; gtk_window_deiconify(w); gtk_window_maximize(w); break; case OVERLAPPED: fullscreen = false; gtk_window_deiconify(w); gtk_window_unmaximize(w); break; case FULLSCREEN: gtk_window_fullscreen(w); fullscreen = true; break; } } void TopWindow::Minimize(bool effect) { SetMode(MINIMIZED); } TopWindow& TopWindow::FullScreen(bool b) { SetMode(b ? (int)FULLSCREEN : (int)OVERLAPPED); return *this; } void TopWindow::Maximize(bool effect) { SetMode(MAXIMIZED); } void TopWindow::Overlap(bool effect) { SetMode(OVERLAPPED); } TopWindow& TopWindow::TopMost(bool b, bool) { GuiLock __; topmost = b; SyncTopMost(); return *this; } bool TopWindow::IsTopMost() const { GuiLock __; return topmost; } void TopWindow::GuiPlatformConstruct() { topmost = false; } void TopWindow::GuiPlatformDestruct() { } void TopWindow::SerializePlacement(Stream& s, bool reminimize) { GuiLock __; int version = 0; s / version; Rect rect = GetRect(); s % overlapped % rect; bool mn = state == MINIMIZED; bool mx = state == MAXIMIZED; s.Pack(mn, mx); LLOG("TopWindow::SerializePlacement / " << (s.IsStoring() ? "write" : "read")); LLOG("minimized = " << mn << ", maximized = " << mx); LLOG("rect = " << rect << ", overlapped = " << overlapped); if(s.IsLoading()) { if(mn) rect = overlapped; Rect limit = GetVirtualWorkArea(); Rect fm = frameMargins; limit.left += fm.left; limit.right -= fm.right; limit.top += fm.top; limit.bottom -= fm.bottom; Size sz = min(rect.Size(), limit.Size()); rect = RectC( minmax(rect.left, limit.left, limit.right - sz.cx), minmax(rect.top, limit.top, limit.bottom - sz.cy), sz.cx, sz.cy); state = OVERLAPPED; if(mn && reminimize) state = MINIMIZED; if(mx) state = MAXIMIZED; if(state == OVERLAPPED) SetRect(rect); if(IsOpen()) { if(state == MINIMIZED) Minimize(false); if(state == MAXIMIZED) Maximize(false); } } } } #endif