diff --git a/src/modules/ctypes/gdk.jsm b/src/modules/ctypes/gdk.jsm index 6cbeb48..5e5e600 100644 --- a/src/modules/ctypes/gdk.jsm +++ b/src/modules/ctypes/gdk.jsm @@ -108,6 +108,10 @@ function gdk_defines(lib) { this.GDK_GRAB_BROKEN = 35; this.GDK_DAMAGE = 36; this.GDK_EVENT_LAST = 37; /* helper variable for decls */ + this.GdkPropMode = ctypes.int; // enum + this.GDK_PROP_MODE_REPLACE = 0; + this.GDK_PROP_MODE_PREPEN = 1; + this.GDK_PROP_MODE_APPEND = 2; this.GdkWindow = ctypes.StructType("GdkWindow"); this.GdkByteOrder = ctypes.int; // enum @@ -176,6 +180,7 @@ function gdk_defines(lib) { { "changed_mask": this.GdkWindowState }, { "new_window_state": this.GdkWindowState }, ]); + this.GdkAtom = ctypes.StructType("GdkAtom"); this.GdkFilterFunc_t = ctypes.FunctionType( ctypes.default_abi, this.GdkFilterReturn, @@ -225,6 +230,8 @@ function gdk_defines(lib) { lib.lazy_bind("gdk_drawable_get_size", ctypes.void_t, this.GdkDrawable.ptr, gobject.gint.ptr, gobject.gint.ptr); // lib.lazy_bind("gdk_window_get_geometry", ctypes.void_t, this.GdkWindow.ptr, gobject.gint.ptr, gobject.gint.ptr, gobject.gint.ptr, gobject.gint.ptr, gobject.gint.ptr); lib.lazy_bind("gdk_window_move_resize", ctypes.void_t, this.GdkWindow.ptr, gobject.gint, gobject.gint, gobject.gint, gobject.gint); + lib.lazy_bind("gdk_atom_intern", this.GdkAtom, gobject.gchar.ptr, gobject.gboolean); + lib.lazy_bind("gdk_property_change", ctypes.void_t, this.GdkWindow.ptr, this.GdkAtom, this.GdkAtom, gobject.gint, this.GdkPropMode, gobject.guchar.ptr, gobject.gint); } diff --git a/src/modules/ctypes/x11.jsm b/src/modules/ctypes/x11.jsm index 72236b7..97c8a78 100644 --- a/src/modules/ctypes/x11.jsm +++ b/src/modules/ctypes/x11.jsm @@ -34,7 +34,8 @@ const XATOMS_EWMH_WM_STATES = [ "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW", "_NET_WM_STATE_DEMANDS_ATTENTION" ]; -const XATOMS = XATOMS_ICCCM.concat(XATOMS_EWMH_WM_STATES).concat(XATOMS_EWMH_GENERAL); +const XATOMS = XATOMS_ICCCM.concat(XATOMS_EWMH_WM_STATES) + .concat(XATOMS_EWMH_GENERAL).concat(["CARDINAL"]); function x11_defines(lib) { @@ -55,35 +56,43 @@ function x11_defines(lib) { } // X.h - this.Success = 0; - this.None = 0; - this.AnyPropertyType = 0; - this.BadValue = 2; - this.BadWindow = 3; - this.BadAtom = 5; - this.BadMatch = 8; - this.BadAlloc = 11; + this.Success = 0; + this.None = 0; + this.AnyPropertyType = 0; + this.BadValue = 2; + this.BadWindow = 3; + this.BadAtom = 5; + this.BadMatch = 8; + this.BadAlloc = 11; this.PropertyNewValue = 0; - this.PropertyDelete = 1; + this.PropertyDelete = 1; + this.PropModeReplace = 0; + this.PropModePrepend = 1; + this.PropModeAppend = 2; // Event names - this.DestroyNotify = 17; - this.UnmapNotify = 18; - this.MapNotify = 19; + this.DestroyNotify = 17; + this.UnmapNotify = 18; + this.MapNotify = 19; this.PropertyNotify = 28; - this.ClientMessage = 33; + this.ClientMessage = 33; // Xutils.h: definitions for initial window state this.WithdrawnState = 0; /* for windows that are not mapped */ - this.NormalState = 1; /* most applications want to start this way */ - this.IconicState = 3; /* application wants to start as an icon */ + this.NormalState = 1; /* most applications want to start this way */ + this.IconicState = 3; /* application wants to start as an icon */ // Xatom - this.XA_ATOM = 4; + this.XA_ATOM = 4; + this.XA_CARDINAL = 6; + // Input Event Masks + this.SubstructureNotifyMask = 1<<19; + this.SubstructureRedirectMask = 1<<20; this.Bool = ctypes.int; + this.Status = ctypes.int; this.Display = ctypes.StructType("Display"); // union not supported by js-ctypes // https://bugzilla.mozilla.org/show_bug.cgi?id=535378 "You can always // typecast pointers, at least as long as you know which type is the biggest" - this.XEvent = ctypes.void_t; + this.XEvent = ctypes.void_t; // union this.XAnyEvent = ctypes.StructType("XAnyEvent", [ { "type": ctypes.int }, { "serial": ctypes.unsigned_long }, @@ -116,6 +125,9 @@ function x11_defines(lib) { lib.lazy_bind("XInternAtom", this.Atom, this.Display.ptr, ctypes.char.ptr, this.Bool); // only_if_exsits lib.lazy_bind("XGetWindowProperty", ctypes.int, this.Display.ptr, this.Window, this.Atom, ctypes.long, ctypes.long, this.Bool, this.Atom, this.Atom.ptr, ctypes.int.ptr, ctypes.unsigned_long.ptr, ctypes.unsigned_long.ptr, ctypes.unsigned_char.ptr.ptr); lib.lazy_bind("XChangeProperty", ctypes.int, this.Display.ptr, this.Window, this.Atom, this.Atom, ctypes.int, ctypes.int, ctypes.unsigned_char.ptr, ctypes.int); + lib.lazy_bind("XDefaultRootWindow", this.Window, this.Display.ptr); + lib.lazy_bind("XSendEvent", this.Status, this.Display.ptr, this.Window, this.Bool, ctypes.long, this.XEvent.ptr); + } if (!x11) { @@ -149,67 +161,3 @@ typedef unsigned long Atom; typedef CARD32 Atom; # endif */ - -/* -XEvent { - int type; - XAnyEvent xany; - XKeyEvent xkey; - XButtonEvent xbutton; - XMotionEvent xmotion; - XCrossingEvent xcrossing; - XFocusChangeEvent xfocus; - XExposeEvent xexpose; - XGraphicsExposeEvent xgraphicsexpose; - XNoExposeEvent xnoexpose; - XVisibilityEvent xvisibility; - XCreateWindowEvent xcreatewindow; - XDestroyWindowEvent xdestroywindow; - XUnmapEvent xunmap; - XMapEvent xmap; - XMapRequestEvent xmaprequest; - XReparentEvent xreparent; - XConfigureEvent xconfigure; - XGravityEvent xgravity; - XResizeRequestEvent xresizerequest; - XConfigureRequestEvent xconfigurerequest; - XCirculateEvent xcirculate; - XCirculateRequestEvent xcirculaterequest; - XPropertyEvent xproperty; - XSelectionClearEvent xselectionclear; - XSelectionRequestEvent xselectionrequest; - XSelectionEvent xselection; - XColormapEvent xcolormap; - XClientMessageEvent xclient; - XMappingEvent xmapping; - XErrorEvent xerror; - XKeymapEvent xkeymap; - XGenericEvent xgeneric; - XGenericEventCookie xcookie; - long pad[24]; -} - -GdkEvent { - GdkEventType type; - GdkEventAny any; - GdkEventExpose expose; - GdkEventNoExpose no_expose; - GdkEventVisibility visibility; - GdkEventMotion motion; - GdkEventButton button; - GdkEventScroll scroll; - GdkEventKey key; - GdkEventCrossing crossing; - GdkEventFocus focus_change; - GdkEventConfigure configure; - GdkEventProperty property; - GdkEventSelection selection; - GdkEventOwnerChange owner_change; - GdkEventProximity proximity; - GdkEventClient client; - GdkEventDND dnd; - GdkEventWindowState window_state; - GdkEventSetting setting; - GdkEventGrabBroken grab_broken; -}; -*/ diff --git a/src/modules/gtk2/FiretrayWindow.jsm b/src/modules/gtk2/FiretrayWindow.jsm index 88b117e..7628114 100644 --- a/src/modules/gtk2/FiretrayWindow.jsm +++ b/src/modules/gtk2/FiretrayWindow.jsm @@ -176,18 +176,20 @@ firetray.Window = { firetray.Handler.windows[xid].savedWidth, firetray.Handler.windows[xid].savedHeight, false); // repaint + + ['savedX', 'savedX', 'savedWidth', 'savedHeight'].forEach(function(element, index, array) { + delete firetray.Handler.windows[xid][element]; + }); }, saveWindowStates: function(xid) { - // TODO: we may want to restore the window onto its original - // desktop/monitor/etc. let winStates = firetray.Window.getXWindowStates(x11.Window(xid)); - firetray.Handler.windows[xid].savedWindowStates = winStates; + firetray.Handler.windows[xid].savedStates = winStates; LOG("save: windowStates="+winStates); }, restoreWindowStates: function(xid) { - let winStates = firetray.Handler.windows[xid].savedWindowStates; + let winStates = firetray.Handler.windows[xid].savedStates; LOG("restored WindowStates: " + winStates); if (winStates & FIRETRAY_XWINDOW_MAXIMIZED) { firetray.Handler.windows[xid].chromeWin.maximize(); @@ -196,6 +198,36 @@ firetray.Window = { if (!hides_on_minimize && (winStates & FIRETRAY_XWINDOW_HIDDEN)) { firetray.Handler.windows[xid].chromeWin.minimize(); } + + delete firetray.Handler.windows[xid].savedStates; + }, + + saveWindowDesktop: function(xid) { + let winDesktop = firetray.Window.getXWindowDesktop(x11.Window(xid)); + firetray.Handler.windows[xid].savedDesktop = winDesktop; + LOG("save: windowDesktop="+winDesktop); + }, + + restoreWindowDesktop: function(xid) { + let desktopDest = firetray.Handler.windows[xid].savedDesktop; + if (desktopDest === null) return; + + let xev = new x11.XClientMessageEvent; + xev.type = x11.ClientMessage; + xev.window = x11.Window(xid); + xev.message_type = x11.current.Atoms._NET_WM_DESKTOP; + xev.format = 32; + xev.data[0] = desktopDest; + + let rootWin = x11.XDefaultRootWindow(x11.current.Display); + let propagate = false; + let mask = ctypes.long(x11.SubstructureNotifyMask|x11.SubstructureRedirectMask); + // fortunately, it's OK not to cast xev. ctypes.cast to a void_t doesn't work (length pb) + let status = x11.XSendEvent(x11.current.Display, rootWin, propagate, mask, xev.address()); + // always returns 1 (BadRequest as a coincidence) + + LOG("restored to desktop: "+desktopDest); + delete firetray.Handler.windows[xid].savedDesktop; }, /* KEPT FOR LATER USE @@ -213,12 +245,12 @@ firetray.Window = { */ /** - * YOU MUST x11.XFree() THE VARIABLE RETURN BY THIS FUNCTION + * YOU MUST x11.XFree() THE VARIABLE RETURNED BY THIS FUNCTION * @param xwin: a x11.Window * @param prop: a x11.Atom */ getXWindowProperties: function(xwin, prop) { - // infos returned by XGetWindowProperty() + // infos returned by XGetWindowProperty() - FIXME: should be freed ? let actual_type = new x11.Atom; let actual_format = new ctypes.int; let nitems = new ctypes.unsigned_long; @@ -229,7 +261,8 @@ firetray.Window = { let offset = 0; let res = x11.XGetWindowProperty( x11.current.Display, xwin, prop, offset, bufSize, 0, x11.AnyPropertyType, - actual_type.address(), actual_format.address(), nitems.address(), bytes_after.address(), prop_value.address()); + actual_type.address(), actual_format.address(), nitems.address(), + bytes_after.address(), prop_value.address()); LOG("XGetWindowProperty res="+res+", actual_type="+actual_type.value+", actual_format="+actual_format.value+", bytes_after="+bytes_after.value+", nitems="+nitems.value); if (!strEquals(res, x11.Success)) { @@ -264,19 +297,20 @@ firetray.Window = { getXWindowStates: function(xwin) { let winStates = 0; - let [propsFound, nitems] = firetray.Window.getXWindowProperties(xwin, x11.current.Atoms._NET_WM_STATE); + let [propsFound, nitems] = + firetray.Window.getXWindowProperties(xwin, x11.current.Atoms._NET_WM_STATE); LOG("propsFound, nitems="+propsFound+", "+nitems); if (!propsFound) return 0; let maximizedHorz = maximizedVert = false; for (let i=0, len=nitems.value; i