Class: Teek::Window

Inherits:
Object
  • Object
show all
Defined in:
lib/teek/window.rb

Overview

A single toplevel window, addressed by its Tk path - the window-scoped counterpart to Widget (which covers any widget of any type). Groups every wm subcommand alongside composite window-lifecycle behaviors (on_close, grab_set/grab_release, modal) that would otherwise keep growing as more and more +window:+-kwarg methods flattened onto App

  • app.window(path).thing reads better than threading window: through a dozen unrelated top-level methods, and gives callers (like teek-ui's DSL) one coherent object per window instead of loose parts.

App#wm (Wm) and App's own window_title/set_window_title/etc. convenience methods, plus App#on_close/#grab_set/#grab_release/ #modal, all delegate here internally - nothing about those public methods changed, this is where their actual work happens now.

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, path) ⇒ Window

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Window.



24
25
26
27
# File 'lib/teek/window.rb', line 24

def initialize(app, path)
  @app = app
  @path = path.to_s
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



21
22
23
# File 'lib/teek/window.rb', line 21

def path
  @path
end

Instance Method Details

#deiconifyvoid

This method returns an undefined value.

Show the window (map it if withdrawn/iconified).



73
74
75
# File 'lib/teek/window.rb', line 73

def deiconify
  @app.tcl_invoke('wm', 'deiconify', @path)
end

#geometryString

Returns geometry string (e.g. +"400x300+0+0"+).

Returns:

  • (String)

    geometry string (e.g. +"400x300+0+0"+)



48
49
50
# File 'lib/teek/window.rb', line 48

def geometry
  @app.tcl_invoke('wm', 'geometry', @path)
end

#grab_releasevoid

This method returns an undefined value.

Release a grab previously set with #grab_set. Safe to call even if the window never held the grab - Tk itself treats that as a no-op.



131
132
133
134
# File 'lib/teek/window.rb', line 131

def grab_release
  @app.tcl_invoke('grab', 'release', @path)
  nil
end

#grab_set(global: false) ⇒ void

This method returns an undefined value.

Set the input grab on the window - while held, mouse and keyboard events outside it (and its descendants) are redirected to it, the building block #modal uses. grab is its own Tcl command family, separate from wm.

Parameters:

  • global (Boolean) (defaults to: false)

    a global grab blocks input to every other application too, not just this one - almost never what you want; local (the default) is scoped to this application.

See Also:



120
121
122
123
124
125
126
# File 'lib/teek/window.rb', line 120

def grab_set(global: false)
  args = ['grab', 'set']
  args << '-global' if global
  args << @path
  @app.tcl_invoke(*args)
  nil
end

This method returns an undefined value.

Make the window modal: grabs input and sets focus on it immediately. Release it explicitly with #grab_release (typically from the window's own dismiss/close handling) when the dialog is done - the grab is NOT released automatically just because this method returns, since a modal dialog is meant to stay grabbed for its whole visible lifetime, not just its setup.

Two safety nets guard against a stuck grab locking out the rest of the display: if the window is destroyed while still grabbed (a crash mid-modal, or just forgetting to call #grab_release first), a binding releases it; if the optional setup block itself raises, the grab is released immediately rather than left dangling on a half-shown dialog.

Examples:

settings = app.window(settings_path)
settings.modal { settings.deiconify }
# ... later, from the window's own on_close/dismiss handler ...
settings.grab_release

Parameters:

  • global (Boolean) (defaults to: false)

Yields:

  • optional - runs with the grab and focus already set

See Also:



161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/teek/window.rb', line 161

def modal(global: false)
  grab_set(global: global)
  # -force: a modal dialog should own keyboard focus immediately, not
  # merely be first in line whenever the app next happens to get it
  # (plain `focus` only takes effect once the app already has input
  # focus at the OS/WM level).
  @app.tcl_invoke('focus', '-force', @path)
  @app.bind(@path, 'Destroy') { grab_release }
  yield if block_given?
  nil
rescue
  grab_release
  raise
end

#on_close { ... } ⇒ void

This method returns an undefined value.

Register a handler for the window manager's close button (WM_DELETE_WINDOW - the titlebar close box, Cmd-W, Alt-F4, etc., depending on platform).

Tk's own default behavior (destroy the window) only applies when nothing else has claimed this protocol - setting a handler here replaces it, so the block is entirely responsible for deciding whether the window actually closes. Call App#destroy yourself if you want it to; do nothing (or show a confirmation first) if you don't.

Examples:

Confirm before quitting

app.window.on_close { app.destroy('.') if app.message_box(message: 'Quit?', type: :yesno) == :yes }

A toplevel that just hides instead of closing

app.window(settings_window).on_close { app.window(settings_window).withdraw }

Yields:

  • called when the window's close button is pressed

See Also:



104
105
106
107
108
# File 'lib/teek/window.rb', line 104

def on_close(&block)
  cb = @app.register_callback(block, relay_break_continue: false)
  @app.callback_registry.reconcile([:wm_protocol, @path]) { |before| before.merge('WM_DELETE_WINDOW' => cb) }
  @app.tcl_eval("wm protocol #{@path} WM_DELETE_WINDOW {ruby_callback #{cb}}")
end

#resizableArray(Boolean, Boolean)

Returns [width_resizable, height_resizable].

Returns:

  • (Array(Boolean, Boolean))

    [width_resizable, height_resizable]



59
60
61
62
# File 'lib/teek/window.rb', line 59

def resizable
  parts = @app.tcl_invoke('wm', 'resizable', @path).split
  [@app.tcl_to_bool(parts[0]), @app.tcl_to_bool(parts[1])]
end

#set_geometry(value) ⇒ String

Returns the geometry.

Parameters:

  • value (String)

    new geometry (e.g. "400x300", +"400x300+100+50"+)

Returns:

  • (String)

    the geometry



54
55
56
# File 'lib/teek/window.rb', line 54

def set_geometry(value)
  @app.tcl_invoke('wm', 'geometry', @path, value.to_s)
end

#set_resizable(width, height) ⇒ void

This method returns an undefined value.

Parameters:

  • width (Boolean)

    allow horizontal resize

  • height (Boolean)

    allow vertical resize



67
68
69
# File 'lib/teek/window.rb', line 67

def set_resizable(width, height)
  @app.tcl_invoke('wm', 'resizable', @path, @app.bool_to_tcl(width), @app.bool_to_tcl(height))
end

#set_title(value) ⇒ String

Returns the title.

Parameters:

  • value (String)

    new title

Returns:

  • (String)

    the title



43
44
45
# File 'lib/teek/window.rb', line 43

def set_title(value)
  @app.tcl_invoke('wm', 'title', @path, value.to_s)
end

#titleString

Returns the window's current title.

Returns:

  • (String)

    the window's current title



37
38
39
# File 'lib/teek/window.rb', line 37

def title
  @app.tcl_invoke('wm', 'title', @path)
end

#to_sString

Returns the Tk window path.

Returns:

  • (String)

    the Tk window path



30
31
32
# File 'lib/teek/window.rb', line 30

def to_s
  @path
end

#withdrawvoid

This method returns an undefined value.

Hide the window without destroying it.



79
80
81
# File 'lib/teek/window.rb', line 79

def withdraw
  @app.tcl_invoke('wm', 'withdraw', @path)
end