// create creates the window, initializes the keybind and mousebind packages // and sets up the window to act like a real top-level client. func (w *window) create() { keybind.Initialize(w.X) mousebind.Initialize(w.X) err := w.CreateChecked(w.X.RootWin(), 0, 0, flagWidth, flagHeight, xproto.CwBackPixel, 0xffffff) if err != nil { errLg.Fatalf("Could not create window: %s", err) } // Make the window close gracefully using the WM_DELETE_WINDOW protocol. w.WMGracefulClose(func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) keybind.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) w.Destroy() xevent.Quit(w.X) }) // Set WM_STATE so it is interpreted as top-level and is mapped. err = icccm.WmStateSet(w.X, w.Id, &icccm.WmState{ State: icccm.StateNormal, }) if err != nil { // not a fatal error lg("Could not set WM_STATE: %s", err) } // _NET_WM_STATE = _NET_WM_STATE_NORMAL ewmh.WmStateSet(w.X, w.Id, []string{"_NET_WM_STATE_NORMAL"}) // Set the name to something. w.nameSet("Decoding all images...") w.Map() }
func grabKeyboardAndMouse(m *Manager) { if m == nil { return } //go func() { X, err := xgbutil.NewConn() if err != nil { logger.Info("Get New Connection Failed:", err) return } keybind.Initialize(X) mousebind.Initialize(X) err = keybind.GrabKeyboard(X, X.RootWin()) if err != nil { logger.Info("Grab Keyboard Failed:", err) return } grabAllMouseButton(X) xevent.ButtonPressFun( func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) { dbus.Emit(m, "KeyReleaseEvent", "") ungrabAllMouseButton(X) keybind.UngrabKeyboard(X) logger.Info("Button Press Event") xevent.Quit(X) }).Connect(X, X.RootWin()) xevent.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { value := parseKeyEnvent(X, e.State, e.Detail) pressKeyStr = value dbus.Emit(m, "KeyPressEvent", value) }).Connect(X, X.RootWin()) xevent.KeyReleaseFun( func(X *xgbutil.XUtil, e xevent.KeyReleaseEvent) { if strings.ToLower(pressKeyStr) == "super_l" || strings.ToLower(pressKeyStr) == "super_r" { pressKeyStr = "Super" } dbus.Emit(m, "KeyReleaseEvent", pressKeyStr) pressKeyStr = "" ungrabAllMouseButton(X) keybind.UngrabKeyboard(X) logger.Infof("Key: %s\n", pressKeyStr) xevent.Quit(X) }).Connect(X, X.RootWin()) xevent.Main(X) //}() }
func initialize() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } mousebind.Initialize(X) xWindow := newWindow(X, INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT) go xevent.Main(X) xorg.Initialize( egl.NativeWindowType(uintptr(xWindow.Id)), xorg.DefaultConfigAttributes, xorg.DefaultContextAttributes) }
func initEGL(controlCh *controlCh, width, height int) *platform.EGLState { X, err := xgbutil.NewConn() if err != nil { panic(err) } mousebind.Initialize(X) keybind.Initialize(X) xWindow := newWindow(controlCh, X, width, height) go xevent.Main(X) return xorg.Initialize( egl.NativeWindowType(uintptr(xWindow.Id)), xorg.DefaultConfigAttributes, xorg.DefaultContextAttributes, ) }
func initialize() { var err error X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } mousebind.Initialize(X) newWindow(X) go xevent.Main(X) display = egl.GetDisplay(egl.DEFAULT_DISPLAY) if ok := egl.Initialize(display, nil, nil); !ok { egl.LogError(egl.GetError()) } if ok := egl.ChooseConfig(display, attr, &config, 1, &numConfig); !ok { egl.LogError(egl.GetError()) } if ok := egl.GetConfigAttrib(display, config, egl.NATIVE_VISUAL_ID, &vid); !ok { egl.LogError(egl.GetError()) } egl.BindAPI(egl.OPENGL_ES_API) context = egl.CreateContext(display, config, egl.NO_CONTEXT, nil) surface = egl.CreateWindowSurface(display, config, egl.NativeWindowType(uintptr(X.RootWin())), nil) var val egl.Int if ok := egl.QuerySurface(display, &val, egl.WIDTH, surface); !ok { egl.LogError(egl.GetError()) } if ok := egl.QuerySurface(display, &val, egl.HEIGHT, surface); !ok { egl.LogError(egl.GetError()) } if ok := egl.GetConfigAttrib(display, config, egl.SURFACE_TYPE, &val); !ok { egl.LogError(egl.GetError()) } gl.ClearColor(0.0, 0, 0, 1.0) p := Program(FragmentShader(fsh), VertexShader(vsh)) gl.UseProgram(p) gl.BindAttribLocation(p, gl.Uint(attrPos), "pos") gl.BindAttribLocation(p, gl.Uint(attrColor), "color") uMatrix = gl.Int(gl.GetUniformLocation(p, "modelviewProjection")) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Anytime the mousebind (keybind) package is used, mousebind.Initialize // *should* be called once. In the case of the mousebind package, this // isn't strictly necessary (currently!), but the 'Drag' features of // the mousebind package won't work without it. mousebind.Initialize(X) // Create two windows to prove we can close one while keeping the // other alive. newWindow(X) newWindow(X) xevent.Main(X) }
// newWindow creates the window, initializes the keybind and mousebind packages // and sets up the window to act like a real top-level client. func newWindow(X *xgbutil.XUtil) *Window { w, err := xwindow.Generate(X) if err != nil { errLg.Fatalf("Could not create window: %s", err) } keybind.Initialize(w.X) mousebind.Initialize(w.X) err = w.CreateChecked(w.X.RootWin(), 0, 0, 600, 600, xproto.CwBackPixel, 0xffffff) if err != nil { errLg.Fatalf("Could not create window: %s", err) } // Make the window close gracefully using the WM_DELETE_WINDOW protocol. w.WMGracefulClose(func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) keybind.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) w.Destroy() xevent.Quit(w.X) }) // Set WM_STATE so it is interpreted as top-level and is mapped. err = icccm.WmStateSet(w.X, w.Id, &icccm.WmState{State: icccm.StateNormal}) if err != nil { lg("Could not set WM_STATE: %s", err) } // _NET_WM_STATE = _NET_WM_STATE_NORMAL // not needed because we we set FS later anyway? //ewmh.WmStateSet(w.X, w.Id, []string{"_NET_WM_STATE_NORMAL"}) w.Map() err = ewmh.WmStateReq(w.X, w.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN") if err != nil { lg("Failed to go FullScreen:", err) } return &Window{w} }
func main() { if flagWriteConfig { writeConfigFiles() os.Exit(0) } X, err := xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Fatalln("Error connecting to X, quitting...") } defer X.Conn().Close() // Do this first! Attempt to retrieve window manager ownership. // This includes waiting for any existing window manager to die. // 'own' also sets up handlers for quitting when a window manager tries // to replace *us*. if err := own(X, flagReplace); err != nil { logger.Error.Fatalf( "Could not establish window manager ownership: %s", err) } if len(flagConfigDir) > 0 { misc.ConfigPaths.Override = flagConfigDir } if len(flagDataDir) > 0 { misc.DataPaths.Override = flagDataDir } misc.ReadData() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) cursors.Initialize(X) wm.Initialize(X, commands.Env, newHacks()) hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini")) // Listen to Root. It is all-important. err = xwindow.New(X, X.RootWin()).Listen( xproto.EventMaskPropertyChange | xproto.EventMaskFocusChange | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect) if err != nil { logger.Error.Fatalf("Could not listen to Root window events: %s", err) } // Update state when the root window changes size wm.RootGeomChangeFun().Connect(X, wm.Root.Id) // Oblige map request events xevent.MapRequestFun( func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) { xclient.New(ev.Window) }).Connect(X, wm.Root.Id) // Oblige configure requests from windows we don't manage. xevent.ConfigureRequestFun( func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) { // Make sure we aren't managing this client. if wm.FindManagedClient(ev.Window) != nil { return } xwindow.New(X, ev.Window).Configure(int(ev.ValueMask), int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height), ev.Sibling, ev.StackMode) }).Connect(X, wm.Root.Id) xevent.FocusInFun( func(X *xgbutil.XUtil, ev xevent.FocusInEvent) { if ignoreRootFocus(ev.Mode, ev.Detail) { return } if len(wm.Workspace().Clients) == 0 { return } wm.FocusFallback() }).Connect(X, wm.Root.Id) // Listen to Root client message events. This is how we handle all // of the EWMH bullshit. xevent.ClientMessageFun(handleClientMessages).Connect(X, wm.Root.Id) // Tell everyone what we support. setSupported() // Start up the IPC command listener. go ipc() // Just before starting the main event loop, check to see if there are // any clients that already exist that we should manage. manageExistingClients() // Now make sure that clients are in the appropriate visible state. for _, wrk := range wm.Heads.Workspaces.Wrks { if wrk.IsVisible() { wrk.Show() } else { wrk.Hide() } } wm.Heads.ApplyStruts(wm.Clients) wm.FocusFallback() wm.Startup = false pingBefore, pingAfter, pingQuit := xevent.MainPing(X) if len(flagCpuProfile) > 0 { f, err := os.Create(flagCpuProfile) if err != nil { logger.Error.Fatalf("%s\n", err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if flagWingoRestarted { hook.Fire(hook.Restarted, hook.Args{}) } else { hook.Fire(hook.Startup, hook.Args{}) } EVENTLOOP: for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case f := <-commands.SafeExec: commands.SafeReturn <- f() case <-pingQuit: break EVENTLOOP } } if wm.Restart { // We need to tell the next invocation of Wingo that it is being // *restarted*. (So that we don't refire the startup hook.) // Thus, search os.Args for "--wingo-restarted". If it doesn't exist, // add it. found := false for _, arg := range os.Args { if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" { found = true } } if !found { os.Args = append(os.Args, "--wingo-restarted") } logger.Message.Println("The user has told us to restart...\n\n\n") if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil { logger.Error.Fatalf("Could not exec '%s': %s", strings.Join(os.Args, " "), err) } } }
func main() { if flagWriteConfig { writeConfigFiles() os.Exit(0) } X, err := xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Fatalln("Error connecting to X, quitting...") } defer X.Conn().Close() if flagShowSocket { showSocketPath(X) return } // Do this first! Attempt to retrieve window manager ownership. // This includes waiting for any existing window manager to die. // 'own' also sets up handlers for quitting when a window manager tries // to replace *us*. if err := own(X, flagReplace); err != nil { logger.Error.Fatalf( "Could not establish window manager ownership: %s", err) } if len(flagConfigDir) > 0 { misc.ConfigPaths.Override = flagConfigDir } if len(flagDataDir) > 0 { misc.DataPaths.Override = flagDataDir } misc.ReadData() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) cursors.Initialize(X) wm.Initialize(X, commands.Env, newHacks()) hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini")) // Initialize event handlers on the root window. rootInit(X) // Tell everyone what we support. setSupported() // Start up the IPC command listener. go ipc(X) // And start up the IPC event notifier. go event.Notifier(X, socketFilePath(X)) // Just before starting the main event loop, check to see if there are // any clients that already exist that we should manage. manageExistingClients() // Now make sure that clients are in the appropriate visible state. for _, wrk := range wm.Heads.Workspaces.Wrks { if wrk.IsVisible() { wrk.Show() } else { wrk.Hide() } } wm.Heads.ApplyStruts(wm.Clients) wm.FocusFallback() wm.Startup = false pingBefore, pingAfter, pingQuit := xevent.MainPing(X) if len(flagCpuProfile) > 0 { f, err := os.Create(flagCpuProfile) if err != nil { logger.Error.Fatalf("%s\n", err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if flagWingoRestarted { hook.Fire(hook.Restarted, hook.Args{}) } else { hook.Fire(hook.Startup, hook.Args{}) } EVENTLOOP: for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case f := <-commands.SafeExec: commands.SafeReturn <- f() case <-pingQuit: break EVENTLOOP } } if wm.Restart { event.Notify(event.Restarting{}) for _, client := range wm.Clients { c := client.(*xclient.Client) if _, ok := c.Frame().(*frame.Full); ok { c.FrameNada() } } time.Sleep(1 * time.Second) // We need to tell the next invocation of Wingo that it is being // *restarted*. (So that we don't refire the startup hook.) // Thus, search os.Args for "--wingo-restarted". If it doesn't exist, // add it. found := false for _, arg := range os.Args { if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" { found = true } } if !found { os.Args = append(os.Args, "--wingo-restarted") } logger.Message.Println("The user has told us to restart...\n\n\n") if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil { logger.Error.Fatalf("Could not exec '%s': %s", strings.Join(os.Args, " "), err) } } }
func main() { X, err := xgbutil.NewConn() fatal(err) // Whenever the mousebind package is used, you must call Initialize. // Similarly for the keybind package. keybind.Initialize(X) mousebind.Initialize(X) // Easter egg! Use a right click to draw a gopher. gopherPng, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) fatal(err) // Now scale it to a reasonable size. gopher := xgraphics.Scale(gopherPng, gopherWidth, gopherHeight) // Create a new xgraphics.Image. It automatically creates an X pixmap for // you, and handles drawing to windows in the XDraw, XPaint and // XSurfaceSet functions. // N.B. An error is possible since X pixmap allocation can fail. canvas := xgraphics.New(X, image.Rect(0, 0, width, height)) // Color in the background color. canvas.For(func(x, y int) xgraphics.BGRA { return bg }) // Use the convenience function XShowExtra to create and map the // canvas window. // XShowExtra will also set the surface window of canvas for us. // We also use XShowExtra to set the name of the window and to quit the // main event loop when the window is closed. win := canvas.XShowExtra("Pointer painting", true) // Listen for pointer motion events and key press events. win.Listen(xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // The mousebind drag function runs three callbacks: one when the drag is // first started, another at each "step" in the drag, and a final one when // the drag is done. // The button sequence (in this case '1') is pressed, the first callback // is executed. If the first return value is true, the drag continues // and a pointer grab is initiated with the cursor id specified in the // second return value (use 0 to keep the cursor unchanged). // If it's false, the drag stops. // Note that Drag will automatically compress MotionNotify events. mousebind.Drag(X, win.Id, win.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawPencil(canvas, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawPencil(canvas, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) mousebind.Drag(X, win.Id, win.Id, "3", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawGopher(canvas, gopher, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawGopher(canvas, gopher, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) // Bind to the clear key specified, and just redraw the bg color. keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { clearCanvas(canvas, win) }).Connect(X, win.Id, clearKey, false) // Bind a callback to each key specified in the 'pencils' color map. // The response is to simply switch the pencil color. for key, clr := range pencils { c := clr keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { log.Printf("Changing pencil color to: %#v", c) pencil = c }).Connect(X, win.Id, key, false) } // Output some basic directions. fmt.Println("Use the left or right buttons on your mouse to paint " + "squares and gophers.") fmt.Println("Pressing numbers 1, 2, 3, 4, 5 or 6 will switch your pencil " + "color.") fmt.Println("Pressing 'c' will clear the canvas.") xevent.Main(X) }
func main() { var err error X, err = xgbutil.NewConn() if err != nil { logger.Error.Println(err) logger.Error.Println("Error connecting to X, quitting...") return } defer X.Conn().Close() keybind.Initialize(X) mousebind.Initialize(X) focus.Initialize(X) stack.Initialize(X) wingo = newWingoState() // Create a root window abstraction and load its geometry wingo.root = xwindow.New(X, X.RootWin()) _, err = wingo.root.Geometry() if err != nil { logger.Error.Println("Could not get ROOT window geometry because: %v", err) logger.Error.Println("Cannot continue. Quitting...") return } // Load configuration wingo.conf, err = loadConfig() if err != nil { logger.Error.Println(err) logger.Error.Println("No configuration found. Quitting...") return } // Load theme wingo.theme, err = loadTheme(X) if err != nil { logger.Error.Println(err) logger.Error.Println("No theme configuration found. Quitting...") return } // Initialize prompts wingo.prompts = newPrompts() wingo.initializeHeads() // Attach all global key bindings attachAllKeys() // Attach all root mouse bindings rootMouseConfig() // Setup some cursors we use cursors.Setup(X) // Listen to Root. It is all-important. wingo.root.Listen(xproto.EventMaskPropertyChange | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect) // Update state when the root window changes size // xevent.ConfigureNotifyFun(rootGeometryChange).Connect(X, wingo.root.Id) // Oblige map request events xevent.MapRequestFun( func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) { newClient(X, ev.Window) }).Connect(X, wingo.root.Id) // Oblige configure requests from windows we don't manage. xevent.ConfigureRequestFun( func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) { flags := int(ev.ValueMask) & ^int(xproto.ConfigWindowSibling) & ^int(xproto.ConfigWindowStackMode) xwindow.New(X, ev.Window).Configure(flags, int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height), ev.Sibling, ev.StackMode) }).Connect(X, wingo.root.Id) // Listen to Root client message events. // We satisfy EWMH with these AND it also provides a mechanism // to issue commands using wingo-cmd. xevent.ClientMessageFun(commandHandler).Connect(X, wingo.root.Id) xevent.Main(X) }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Anytime the mousebind (keybind) package is used, mousebind.Initialize // *should* be called once. In the case of the mousebind package, this // isn't strictly necessary, but the 'Drag' features of the mousebind // package won't work without it. mousebind.Initialize(X) // Before attaching callbacks, wrap them in a callback function type. // The mouse package exposes two such callback types: // mousebind.ButtonPressFun and mousebind.ButtonReleaseFun. cb1 := mousebind.ButtonPressFun( func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) { log.Println("Button press!") }) // We can now attach the callback to a particular window and button // combination. This particular example grabs a button on the root window, // which makes it a global mouse binding. // Also, "Mod4-1" typically corresponds to pressing down the "Super" or // "Windows" key on your keyboard, and then pressing the left mouse button. // The last two parameters are whether to make a synchronous grab and // whether to actually issue a grab, respectively. // (The parameters used here are the common case.) // See the documentation for the Connect method for more details. err = cb1.Connect(X, X.RootWin(), "Mod4-1", false, true) // A mouse binding can fail if the mouse string could not be parsed, or if // you're trying to bind a button that has already been grabbed by another // client. if err != nil { log.Fatal(err) } // We can even attach multiple callbacks to the same button. err = mousebind.ButtonPressFun( func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) { log.Println("A second handler always happens after the first.") }).Connect(X, X.RootWin(), "Mod4-1", false, true) if err != nil { log.Fatal(err) } // Finally, if we want this client to stop responding to mouse events, we // can attach another handler that, when run, detaches all previous // handlers. // This time, we'll show an example of a ButtonRelease binding. err = mousebind.ButtonReleaseFun( func(X *xgbutil.XUtil, e xevent.ButtonReleaseEvent) { // Use mousebind.Detach to detach the root window // from all ButtonPress *and* ButtonRelease handlers. mousebind.Detach(X, X.RootWin()) mousebind.Detach(X, X.RootWin()) log.Printf("Detached all Button{Press,Release}Events from the "+ "root window (%d).", X.RootWin()) }).Connect(X, X.RootWin(), "Mod4-Shift-1", false, true) if err != nil { log.Fatal(err) } // Finally, start the main event loop. This will route any appropriate // ButtonPressEvents to your callback function. log.Println("Program initialized. Start pressing mouse buttons!") xevent.Main(X) }
func main() { // I don't want to retype all of these things // TODO: find/replace fatal with util.Fatal fatal := util.Fatal // establish X connection X, err := xgbutil.NewConn() fatal(err) // initiate extension tools shape.Init(X.Conn()) mousebind.Initialize(X) // Detail our current window manager. Insures a minimum of EWMH compliance wm_name, err := ewmh.GetEwmhWM(X) fatal(err) log.Printf("Window manager: %s\n", wm_name) // create the cross UI cross_ui := makeCross(X) cross := cross_ui.Window // map the icons on the cross the the actions they should perform // when objects are dropped over them win_to_action := make(map[xproto.Window]wm.WindowInteraction) for name, icon := range cross_ui.Icons { if action, ok := wm.Actions[name]; ok { win_to_action[icon.Window.Id] = action } else { // otherwise, // shade the icon because it has no action attatched to it icon.SetState(ui.StateDisabled) } } // define handlers for the three parts of any drag-drop operation dm := util.DragManager{} handleDragStart := func(X *xgbutil.XUtil, rx, ry, ex, ey int) (cont bool, cursor xproto.Cursor) { // find the window we are trying to drag win, err := wm.FindManagedWindowUnderMouse(X) if err != nil { // don't continue the drag log.Printf("DragStart: could not get incoming window: %v\n", err) return false, 0 } // cool awesome! dm.StartDrag(win) // continue the drag return true, 0 } handleDragStep := func(X *xgbutil.XUtil, rx, ry, ex, ey int) { // see if we have a window that ISN'T the incoming window win, err := wm.FindManagedWindowUnderMouse(X) if err != nil { // whatever log.Printf("DragStep: no window found or something: %v\n", err) return } // oh we have a window? and it isn't the start window!? And not the current target!? if win != dm.Incoming && win != dm.Target { // reposition the cross over it // TODO: actually do this, center operates on rects, and all I have is this xproto.Window dm.SetTarget(win) // get the target width/height target_geom, err := xwindow.New(X, win).Geometry() if err != nil { log.Printf("DragStep: issues getting target geometry: %v\n", err) return } // set the target goemetry X, Y to the actual x, y relative to the root window tx, ty, err := wm.TranslateCoordinatesSync(X, win, X.RootWin(), 0, 0) if err != nil { log.Printf("DragStep: issue translating target coordinates to root coordinates: %v\n", err) return } target_geom.XSet(tx) target_geom.YSet(ty) x, y := util.CenterOver(cross.Geom, target_geom) cross.Move(x, y) cross.Map() } } handleDragEnd := func(X *xgbutil.XUtil, rx, ry, ex, ey int) { exit_early := false // get icon we are dropping over icon_win, _, err := wm.FindNextUnderMouse(X, cross.Id) if err != nil { log.Printf("DragEnd: icon not found: %v\n", err) exit_early = true } incoming, target, err := dm.EndDrag() // drag manager produces errors if we don't have both an Incoming and a Target yet if err != nil { log.Printf("DragEnd: drag manager state error: %v\n", err) exit_early = true } // we tried: hide UI cross.Unmap() // we had some sort of error, escape! if exit_early { return } // retrieve the action that this icon indicates if action, ok := win_to_action[icon_win]; ok { // create util-window objects from our window IDs if incoming_id, inc_ok := incoming.(xproto.Window); inc_ok { inc_win := xwindow.New(X, incoming_id) if target_id, t_ok := target.(xproto.Window); t_ok { t_win := xwindow.New(X, target_id) // perform the action! action(t_win, inc_win) } else { log.Println("DragEnd: target type error (was %v)\n", target) } } else { log.Println("DragEnd: incoming type error (was %v)\n", incoming) } } else { log.Printf("DragEnd: couldn't map window %v to an action", icon_win) } } mousebind.Drag(X, X.RootWin(), X.RootWin(), KeyComboMove, true, handleDragStart, handleDragStep, handleDragEnd) /////////////////////////////////////////////////////////////////////////// // Window resizing behavior spike ManageResizingWindows(X) // start event loop, even though we have no events // to keep app from just closing xevent.Main(X) }
func openWin(X *xgbutil.XUtil) *xwindow.Window { mousebind.Initialize(X) win := newWindow(X, WINDOW_WIDTH, WINDOW_HEIGHT) go xevent.Main(X) return win }