class Demo::ChangeDisplay

Constants

DISPLAY_COLUMN_DISPLAY
SCREEN_COLUMN_SCREEN

Public Class Methods

new() click to toggle source

Main entry point. If the dialog for this demo doesn't yet exist, creates it. Otherwise, destroys it.

Calls superclass method
# File gtk2/sample/gtk-demo/changedisplay.rb, line 46
def initialize
  @size_group = nil

  @display_model = nil
  @screen_model = nil

  @screen_selection = nil

  @current_display = nil
  @current_screen = nil

  super('Change Screen or display',
        nil, # parent
        Gtk::Dialog::NO_SEPARATOR,
        [Gtk::Stock::CLOSE, Gtk::Dialog::RESPONSE_CLOSE],
        ['Change', Gtk::Dialog::RESPONSE_OK])

  set_default_size(300, 400)
  signal_connect('response') do |dialog, response_id|
    if response_id == Gtk::Dialog::RESPONSE_OK
      if Gtk.check_version?(2, 2, 0)
        query_change_display
      else
        puts "This sample requires GTK+ 2.2.0 or later"
      end
    else
      destroy # Gtk.main_quit?
    end
  end
  signal_connect('destroy') do

  end

  unless Gtk.check_version?(2, 2, 0)
     vbox.add(Gtk::Label.new("This sample requires GTK+ 2.2.0 or later"))
     return
  end

  vbox = Gtk::VBox.new(false, 5)
  vbox.set_border_width(8)

  self.vbox.pack_start(vbox, true, true)

  @size_group = Gtk::SizeGroup.new(Gtk::SizeGroup::HORIZONTAL)

  frame = create_display_frame
  vbox.pack_start(frame, true, true)

  frame = create_screen_frame
  vbox.pack_start(frame, true, true)

  initialize_displays
end

Public Instance Methods

add_display(display) click to toggle source

Adds a new display to our list of displays, and connects to the 'closed' signal so that we can remove it from the list of displays again.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 382
def add_display(display)
  iter = @display_model.append
  iter.set_value(DISPLAY_COLUMN_NAME, display.name)
  iter.set_value(DISPLAY_COLUMN_DISPLAY, display)

  handler_id = display.signal_connect('closed') do
    display_closed_cb(display)
  end

  signal_connect('destroy') do
    display.signal_handler_disconnect(handler_id)
  end
end
create_display_frame() click to toggle source

Creates the 'Display' frame in the main window.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 138
def create_display_frame
  frame, tree_view, button_vbox = create_frame('Display')

  button = left_align_button_new('_Open...')
  button.signal_connect('clicked') do
    open_display_cb
  end
  button_vbox.pack_start(button, false, false, 0)

  button = left_align_button_new('_Close')
  button.signal_connect('clicked') do
    if @current_display
      @current_display.close
    end
  end
  button_vbox.pack_start(button, false, false, 0)

  @display_model = Gtk::ListStore.new(String, Gdk::Display)
  tree_view.model = @display_model

  column = Gtk::TreeViewColumn.new('Name',
                                   Gtk::CellRendererText.new,
                                   {'text' => DISPLAY_COLUMN_NAME})
  tree_view.append_column(column)

  selection = tree_view.selection
  selection.signal_connect('changed') do
    display_changed_cb(selection)
  end

  return frame
end
create_frame(title) click to toggle source

This function is used both for creating the 'Display' and 'Screen' frames, since they have a similar structure. The caller hooks up the right context for the value returned in tree_view, and packs any relevant buttons into button_vbox.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 199
def create_frame(title)
  frame = Gtk::Frame.new(title)

  hbox = Gtk::HBox.new(false, 8)
  hbox.set_border_width(8)
  frame.add(hbox)

  scrollwin = Gtk::ScrolledWindow.new
  scrollwin.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC)
  scrollwin.shadow_type = Gtk::SHADOW_IN
  hbox.pack_start(scrollwin, true, true)

  tree_view = Gtk::TreeView.new
  tree_view.headers_visible = false
  scrollwin.add(tree_view)

  selection = tree_view.selection
  selection.mode = Gtk::SELECTION_BROWSE

  button_vbox = Gtk::VBox.new(false, 5)
  hbox.pack_start(button_vbox, false, false)

  @size_group.add_widget(button_vbox)

  return frame, tree_view, button_vbox
end
create_screen_frame() click to toggle source

Creates the 'Screen' frame in the main window.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 172
def create_screen_frame
  frame, tree_view, button_vbox = create_frame('Screen')

  @screen_model = Gtk::ListStore.new(Integer, Gdk::Screen)
  tree_view.model = @screen_model

  column = Gtk::TreeViewColumn.new('Number',
                                   Gtk::CellRendererText.new,
                                   {'text' => SCREEN_COLUMN_NUMBER})
  tree_view.append_column(column)

  @screen_selection = tree_view.selection
  @screen_selection.signal_connect('changed') do |selection|
    @current_screen = if iter = selection.selected
                        iter.get_value(SCREEN_COLUMN_SCREEN)
                      else
                        nil
                      end
  end

  return frame
end
display_changed_cb(selection) click to toggle source

Called when the selected row in the display list changes. Updates info.current_display, then refills the list of screens.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 369
def display_changed_cb(selection)
  @current_display =
    if iter = selection.selected
      iter.get_value(DISPLAY_COLUMN_DISPLAY)
    else
      nil
    end
  fill_screens
end
display_closed_cb(display) click to toggle source

Called when one of the currently open displays is closed. Remove it from our list of displays.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 398
def display_closed_cb(display)
  @display_model.each do |model, path, iter|
    tmp_display = iter.get_value( DISPLAY_COLUMN_DISPLAY)
    if tmp_display == display
      @display_model.remove(iter)
      break
    end
  end
end
fill_screens() click to toggle source

Fills in the screen list based on the current display

# File gtk2/sample/gtk-demo/changedisplay.rb, line 119
def fill_screens
  @screen_model.clear

  if @current_display
    n_screens = @current_display.n_screens

    n_screens.times do |i|
      iter = @screen_model.append
      iter.set_value(SCREEN_COLUMN_NUMBER, i)
      iter.set_value(SCREEN_COLUMN_SCREEN, @current_display.get_screen(i))

      if i == 0
        @screen_selection.select_iter(iter)
      end
    end
  end
end
find_toplevel_at_pointer(display) click to toggle source

Finds the toplevel window under the mouse pointer, if any.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 310
def find_toplevel_at_pointer(display)
  pointer_window, x, y = display.window_at_pointer

  # The user data field of a GdkWindow is used to store a pointer
  # to the widget that created it.
  if pointer_window
    widget = pointer_window.user_data
  end

  return (if widget
            widget.toplevel
          else
            nil
          end)
end
initialize_displays() click to toggle source

Adds all currently open displays to our list of displays, and set up a signal connection so that we'll be notified when displays are opened in the future as well.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 103
def initialize_displays
  manager = Gdk::DisplayManager.get

  manager.displays.each do |display|
    add_display(display)
  end

  handler_id = manager.signal_connect('display_opened') do |display|
    add_display(display)
  end
  signal_connect('destroy') do
    manager.signal_handler_disconnect(handler_id)
  end
end
left_align_button_new(label) click to toggle source

If we have a stack of buttons, it often looks better if their contents are left-aligned, rather than centered. This function creates a button and left-aligns it contents.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 229
def left_align_button_new(label)
  button = Gtk::Button.new(label, true)
  button.child.set_alignment(0.0, 0.5)

  return button
end
open_display_cb() click to toggle source

Called when the user clicks on 'Open…' in the display frame. Prompts for a new display, and then opens a connection to that display.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 329
def open_display_cb
  dialog = Gtk::Dialog.new('Open Display',
                           self,
                           Gtk::Dialog::MODAL,
                           [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
                           [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK])

  dialog.default_response = Gtk::Dialog::RESPONSE_OK
  display_entry = Gtk::Entry.new
  display_entry.activates_default = true
  dialog_label =
    Gtk::Label.new("Please enter the name of\nthe new display\n")

  dialog.vbox.add(dialog_label)
  dialog.vbox.add(display_entry)

  display_entry.grab_focus
  dialog.vbox.show_all

  result = nil
  until result
    response_id = dialog.run
    break if response_id != Gtk::Dialog::RESPONSE_OK

    new_screen_name = display_entry.text

    unless new_screen_name.empty?
      begin
        result = Gdk::Dispaly.open(new_screen_name)
      rescue
        dialog_label.text = "Can't open display :\n\t%s\nplease try another one\n" % [new_screen_name]
      end
    end
  end
  dialog.destroy
end
query_change_display() click to toggle source

Prompts the user for a toplevel window to move, and then moves that window to the currently selected display

# File gtk2/sample/gtk-demo/changedisplay.rb, line 239
def query_change_display
  screen = self.window.screen

  toplevel = query_for_toplevel(screen,
                                "Please select the toplevel\n"+
                                "to move to the new screen")

  if toplevel
    toplevel.screen = @current_screen
  else
    screen.display.beep
  end
end
query_for_toplevel(screen, prompt) click to toggle source

Asks the user to click on a window, then waits for them click the mouse. When the mouse is released, returns the toplevel window under the pointer, or nil, if there is none.

# File gtk2/sample/gtk-demo/changedisplay.rb, line 256
def query_for_toplevel(screen, prompt)
  toplevel = nil

  display = screen.display

  popup = Gtk::Window.new(Gtk::Window::POPUP)
  popup.screen = screen
  popup.modal = true
  popup.window_position = Gtk::Window::POS_CENTER

  frame = Gtk::Frame.new
  frame.set_shadow_type(Gtk::SHADOW_OUT)
  popup.add(frame)

  label = Gtk::Label.new(prompt)
  label.set_padding(10, 10)
  frame.add(label)

  popup.show_all

  # TODO: Gdk::Cursor.new(screen.display, Gdk::Cursor::CROSSHAIR)
  cursor = Gdk::Cursor.new(Gdk::Cursor::CROSSHAIR)

  if Gdk::pointer_grab(popup.window, false,
                       Gdk::Event::BUTTON_RELEASE_MASK,
                       nil,
                       cursor,
                       Gdk::Event::CURRENT_TIME) == Gdk::GRAB_SUCCESS
    clicked = false

    popup.signal_connect('button-release-event') do
      clicked = true
    end

    # Process events until clicked is set by button_release_event_cb.
    # We pass in may_block = true since we want to wait if there
    # are no events currently.
    until clicked
      Gtk.main_iteration # TODO: GLib::main_context_iteration(nil, true)

      toplevel = find_toplevel_at_pointer(screen.display)
      if toplevel == popup
        toplevel = nil
      end
    end

    popup.destroy
    Gdk.flush # Really release the grab

    return toplevel
  end
end