265 lines
8.3 KiB
D
265 lines
8.3 KiB
D
/* MinWin PeerImpl module
|
|
*
|
|
* Mixin template to implement heavyweight peer for window children.
|
|
* Plus PeerWrapper to insert peer children into the MinWin tree.
|
|
*
|
|
* Written by Ben Hinkle and released to the public domain, as
|
|
* explained at http://creativecommons.org/licenses/publicdomain
|
|
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin
|
|
*/
|
|
|
|
module minwin.peerimpl;
|
|
|
|
private {
|
|
import minwin.app;
|
|
import minwin.component;
|
|
import minwin.window;
|
|
import std.string;
|
|
import minwin.logging;
|
|
}
|
|
|
|
|
|
version (MinWin32) {
|
|
public import minwin.paint;
|
|
private import minwin.mswindows;
|
|
|
|
template WindowChildImpl() {
|
|
|
|
WindowChildPeer peer;
|
|
PeerForAdd getPeerForAdd() { return peer; }
|
|
WindowChildPeer getPeer() { return peer;}
|
|
|
|
void disposePeer(){
|
|
if (hasPeer == OWNS_PEER && parent is null) {
|
|
int ok = DeleteObject(peer);
|
|
sysAssert(ok != false, "Failed to dispose peer child");
|
|
}
|
|
hasPeer = NO_PEER;
|
|
}
|
|
|
|
void visible(bool vis) {
|
|
ShowWindow(peer,vis ? SW_SHOW : SW_HIDE); // ignore bool result
|
|
}
|
|
bool visible() {
|
|
return IsWindowVisible(peer) != 0;
|
|
}
|
|
|
|
void enabled(bool b) {
|
|
EnableWindow(peer, b);
|
|
}
|
|
bool enabled() {
|
|
return IsWindowEnabled(peer) == TRUE;
|
|
}
|
|
|
|
void requestFocus() {
|
|
HWND old = SetFocus(peer);
|
|
sysAssert(old !is null, "Failed to requestFocus");
|
|
}
|
|
|
|
// gets window bounds that encose the entire widget in parent coordinates
|
|
void getBounds(inout Rect r) {
|
|
Rect r2;
|
|
BOOL ok = GetWindowRect(peer,&r2.native);
|
|
sysAssert(ok != false, "Failed to get window bounds");
|
|
int x,y;
|
|
parent.getPeerOffset(x,y);
|
|
r2.LTWH(r2.left+x,r2.top+y,r2.width,r2.height);
|
|
r = r2;
|
|
}
|
|
|
|
void setBounds(inout Rect r) {
|
|
Rect r2,r3 = r;
|
|
getBounds(r2);
|
|
int x,y;
|
|
parent.getPeerOffset(x,y);
|
|
r3.LTWH(r3.left+x,r3.top+y,r3.width,r3.height);
|
|
BOOL ok = MoveWindow(peer,r3.left,r3.top,r3.width,r3.height,true);
|
|
sysAssert(ok != false, "Failed to move window in setBounds");
|
|
if (r2 != r)
|
|
childLayoutDirty = true;
|
|
}
|
|
|
|
alias Component.size size;
|
|
void size(Point s) {
|
|
Rect r2;
|
|
BOOL ok = GetWindowRect(peer,&r2.native);
|
|
sysAssert(ok != false, "Failed to get window rect in size");
|
|
ok = MoveWindow(peer,r2.left,r2.top,s.x,s.y,true);
|
|
sysAssert(ok != false, "Failed to move window in size");
|
|
if (r2.width != s.x || r2.height != s.y)
|
|
childLayoutDirty = true;
|
|
}
|
|
|
|
void repaint() {
|
|
BOOL ok = InvalidateRect(peer,null,clearBackgroundOnPaint);
|
|
sysAssert(ok != false, "Failed to invalidate rect in repaint");
|
|
}
|
|
|
|
GContext getGContext() {
|
|
GContext gc = newGContext();
|
|
gc.peer = GetDC(peer);
|
|
sysAssert(gc.peer !is null, "Failed to get DC in getGContext");
|
|
gc.hasPeer = OWNS_PEER;
|
|
return gc;
|
|
}
|
|
}
|
|
|
|
// Get the Component object associated with the given peer.
|
|
// The peer is accessed from the Component using the peer property.
|
|
WindowChild peerToWindowChild(WindowChildPeer peer) {
|
|
return cast(WindowChild)cast(void*)GetWindowLongA(peer,GWL_USERDATA);
|
|
}
|
|
// Associate c with the peer. On Windows this overwrites the
|
|
// window UserData.
|
|
void setWindowChildPeer(Component c, WindowChildPeer peer,int peerState) {
|
|
SetWindowLongA(peer,GWL_USERDATA,cast(int)cast(void*)c);
|
|
c.hasPeer = peerState;
|
|
// TODO investigate if we need a destroy callback to clear hasPeer
|
|
}
|
|
|
|
} else version(GTK) {
|
|
|
|
private import minwin.gtk;
|
|
|
|
extern (C)
|
|
gint mw_exposechild_callback(GtkWidget w, GdkEventExpose*ev,
|
|
gpointer ud) {
|
|
Component win = cast(Component) ud;
|
|
if (win) {
|
|
win.layout(true);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template WindowChildImpl() {
|
|
|
|
WindowChildPeer peer;
|
|
|
|
PeerForAdd getPeerForAdd() { return peer; }
|
|
WindowChildPeer getPeer() { return peer;}
|
|
|
|
void disposePeer() {
|
|
if (hasPeer == OWNS_PEER && parent is null)
|
|
gtk_widget_destroy(peer);
|
|
hasPeer = NO_PEER;
|
|
}
|
|
|
|
void visible(bool vis) {
|
|
if (vis) {
|
|
gtk_widget_show(peer);
|
|
} else {
|
|
gtk_widget_hide(peer);
|
|
}
|
|
}
|
|
|
|
bool visible() {
|
|
GtkObject* obj = cast(GtkObject*)peer;
|
|
return ((obj.flags & GtkWidgetFlags.GTK_VISIBLE) != 0);
|
|
}
|
|
|
|
void enabled(bool b) {
|
|
gtk_widget_set_sensitive(peer,cast(int)b);
|
|
}
|
|
bool enabled() {
|
|
GtkObject* obj = cast(GtkObject*)peer;
|
|
return ((obj.flags & GtkWidgetFlags.GTK_SENSITIVE) != 0);
|
|
}
|
|
|
|
override void requestFocus() {
|
|
GtkObject* obj = cast(GtkObject*)peer;
|
|
|
|
// printf("%d\n", cast(int)((obj.flags & GtkWidgetFlags.GTK_CAN_FOCUS) != 0));
|
|
gtk_widget_grab_focus(peer);
|
|
}
|
|
|
|
void getBounds(inout Rect r) {
|
|
int x,y,x2,y2,w,h,depth;
|
|
parent.getPeerOffset(x,y);
|
|
// gdk_window_get_geometry(peer.window,&x2,&y2,&w,&h,&depth);
|
|
Rect r2 = toRect(peer.allocation);
|
|
r.LTWH(r2.left+x,r2.top+y,r2.width,r2.height);
|
|
// version(LOG) log.writefln("get bounds got %d %d %d %d",
|
|
// x2+x,y2+y,w,h);
|
|
}
|
|
|
|
void setBounds(inout Rect r) {
|
|
version(LOG) log.writefln("setBounds %d %d %d %d",
|
|
r.left,r.top,r.width,r.height);
|
|
|
|
int x,y;
|
|
parent.getPeerOffset(x,y);
|
|
Rect r2 = r;
|
|
r2.left = r2.left+x;
|
|
r2.top = r2.top+y;
|
|
|
|
gtk_widget_size_allocate(peer,&r2.native);
|
|
/*
|
|
int x2,y2,w,h,depth;
|
|
gdk_window_get_geometry(peer.window,&x2,&y2,&w,&h,&depth);
|
|
r.LTWH(x2+x,y2+y,w,h);
|
|
version(LOG) log.writefln("after set bounds got %d %d %d %d",
|
|
x2,y2,w,h);
|
|
if (r2.width != r.width || r2.height != r.height)
|
|
*/
|
|
childLayoutDirty = true;
|
|
}
|
|
|
|
alias Component.size size;
|
|
void size(Point s) {
|
|
Rect r;
|
|
getBounds(r);
|
|
r.LTWH(r.left,r.top,s.x,s.y);
|
|
setBounds(r);
|
|
}
|
|
|
|
Point preferredSize() {
|
|
GtkRequisition req;
|
|
gtk_widget_size_request(peer,&req);
|
|
int width = req.width;
|
|
int height = req.height;
|
|
if (userPreferredWidth > 0)
|
|
width = userPreferredWidth;
|
|
if (userPreferredHeight > 0)
|
|
height = userPreferredHeight;
|
|
return XY(width,height);
|
|
}
|
|
|
|
// mark as needing a repaint and post event to event queue
|
|
void repaint() {
|
|
Rect r;
|
|
getBounds(r);
|
|
gdk_window_invalidate_rect(peer.window,&r.native,true);
|
|
}
|
|
}
|
|
|
|
WindowChild peerToWindowChild(WindowChildPeer peer) {
|
|
gpointer ptr = g_object_get_data(cast(GObject*)peer,"MinWinUserData");
|
|
return cast(WindowChild)ptr;
|
|
}
|
|
void setWindowChildPeer(Component c, WindowChildPeer peer,int peerState) {
|
|
g_object_set_data(cast(GObject*)peer,"MinWinUserData",cast(gpointer)peer);
|
|
g_signal_connect_data(peer,"destroy",
|
|
cast(GCallback)&mw_wcdestroy_callback,
|
|
cast(gpointer)c,
|
|
null,GConnectFlags.G_CONNECT_AFTER);
|
|
c.hasPeer = peerState;
|
|
}
|
|
extern (C)
|
|
void mw_wcdestroy_callback(GtkObject w, gpointer ud) {
|
|
Component wc = cast(Component) ud;
|
|
if (wc && (wc.hasPeer == OWNS_PEER)) {
|
|
wc.hasPeer = NO_PEER;
|
|
}
|
|
}
|
|
}
|
|
|
|
// assumes the peer has already been parented to the result of
|
|
// parent.getPeerForAdd
|
|
class PeerWrapper : WindowChild {
|
|
this(Component parent, WindowChildPeer peer) {
|
|
this.peer = peer;
|
|
setWindowChildPeer(this,peer,FOREIGN_PEER);
|
|
parent.addChild(this);
|
|
}
|
|
mixin WindowChildImpl!();
|
|
}
|