試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

PyGTKでシステムトレイのアイコンの隣にポップアップウィンドウを作成する(後半)

PyGTKでシステムトレイのアイコンの隣にポップアップウィンドウを作成する(前半)」の続き。

コード例

下のコードを実行してシステムトレイに出たアイコンをクリックすると、トレイアイコンが縦並びのときには横に、横並びのときには縦に長い(比率が1:5の)ポップアップウィンドウが出て、もう一度トレイアイコンをクリックすると消える。

#! /usr/bin/python
# -*- encoding: utf-8 -*-

import sys
import os
try:
  import pygtk
  pygtk.require("2.0")
except:
  pass
try:
  import gtk
except:
  print >> sys.stderr, "Error: PyGTK is not installed"
  sys.exit(1)
if gtk.pygtk_version < (2,10,0):
  errtitle = "Error"
  errmsg = "PyGTK >= 2.10.0 required"
  if gtk.pygtk_version < (2,4,0):
    print >> sys.stderr, errtitle + ": " + errmsg
  else:
    errdlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK)
    errdlg.set_title(errtitle)
    errdlg.set_markup(errmsg)
    errdlg.run()
  sys.exit(1)


class TrayMenu(gtk.Menu):
  """
  システムトレイのメニュー
  """
  def __init__(self, tray):
    gtk.Menu.__init__(self)  # 必須

    self.tray = tray
    self.show = False  # ウィンドウの表示フラグ

    # 終了
    self.item_quit = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
    self.item_quit.connect("activate", self.quit_activate)
    self.append(self.item_quit)

    # 表示可能にする
    self.show_all()
  def activate(self, widget):
    """
    クリックされたときの処理
    """
    # ウィンドウが表示されている場合は壊す
    if self.show == True:
      self.win.destroy()
      self.show = False
    else:
    # 表示されていない場合にウィンドウ作成
      # (画面の情報, 表示領域の情報, 方向の情報) を取得
      (screen, area, orientation) = self.tray.get_geometry()
      print "orientation:", orientation
      print "x:%d y:%d width:%d height:%d\n" % (area.x, area.y, area.width, area.height)
      # ポップアップウィンドウの作成
      self.win = gtk.Window(gtk.WINDOW_POPUP)
      # ドックウィンドウにする場合
#      self.win.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
      # システムトレイアイコンが縦方向に並ぶ場合(パネルが左右端にある場合など)
      if orientation == gtk.ORIENTATION_VERTICAL:
        # 画面右端にある場合は左に表示する
        # アイコンのX座標 + 幅 + (幅 x 5)
        # つまり「アイコンのX座標 + 幅 x (1 + 5)」を画面幅と比較
        if area.x + area.width * (1 + 5) > screen.get_width():
          x      = area.x - area.height * 5
          y      = area.y
          width  = area.width * 5
          height = area.height
        # それ以外は右に表示する
        else:
          x      = area.x + area.height
          y      = area.y
          width  = area.width * 5
          height = area.height
      # システムトレイアイコンが横方向に並ぶ場合(パネルが上下端にある場合など)
      else:
        # 画面上端にある場合は下に表示する
        if area.y < area.height * 5:
          x      = area.x
          y      = area.y + area.height
          width  = area.width
          height = area.height * 5
        # それ以外は上に表示する
        else:
          x      = area.x
          y      = area.y - area.height * 5
          width  = area.width
          height = area.height * 5
      # 上で決めたサイズと位置に調整
      self.win.resize(width, height)
      self.win.move(x, y)
      # ウィンドウを表示
      self.win.show_all()
      self.show = True
  def show_menu(self, widget, button, time):
    self.popup(None, None, gtk.status_icon_position_menu, button, time, self.tray)
  def quit_activate(self, widget):
    """
    終了
    """
    gtk.main_quit()

class PyGTKSystrayGeometryTest:
  """
  システムトレイのアイコンジオメトリテスト
  """
  def main(self):
    tray = gtk.StatusIcon()
    menu = TrayMenu(tray)
    tray.set_from_stock(gtk.STOCK_DIALOG_INFO)
    tray.connect("popup-menu", menu.show_menu)
    tray.connect("activate", menu.activate)
    gtk.main()


if __name__ == "__main__":
  app = PyGTKSystrayGeometryTest()
  app.main()

システムトレイアイコンの並び方向が正常に取得できない環境での例

下はシステムトレイアイコンの並び方向の情報を利用する代わりにシステムトレイアイコンのX座標を用いて、システムトレイを提供するパネル/バーが画面の左右に張り付いているときに横方向(かつ画面の内側)にウィンドウを出すようにしたもの。システムトレイアイコンの位置(X座標)によっては意図しない方向にウィンドウが出てしまうことがある。

#! /usr/bin/python
# -*- encoding: utf-8 -*-

import sys
import os
try:
  import pygtk
  pygtk.require("2.0")
except:
  pass
try:
  import gtk
except:
  print >> sys.stderr, "Error: PyGTK is not installed"
  sys.exit(1)
if gtk.pygtk_version < (2,10,0):
  errtitle = "Error"
  errmsg = "PyGTK >= 2.10.0 required"
  if gtk.pygtk_version < (2,4,0):
    print >> sys.stderr, errtitle + ": " + errmsg
  else:
    errdlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK)
    errdlg.set_title(errtitle)
    errdlg.set_markup(errmsg)
    errdlg.run()
  sys.exit(1)


class TrayMenu(gtk.Menu):
  """
  システムトレイのメニュー
  """
  def __init__(self, tray):
    gtk.Menu.__init__(self)  # 必須

    self.tray = tray
    self.show = False  # ウィンドウの表示フラグ

    # 終了
    self.item_quit = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
    self.item_quit.connect("activate", self.quit_activate)
    self.append(self.item_quit)

    # 表示可能にする
    self.show_all()
  def activate(self, widget):
    """
    クリックされたときの処理
    """
    # ウィンドウが表示されている場合は壊す
    if self.show == True:
      self.win.destroy()
      self.show = False
    else:
    # 表示されていない場合にウィンドウ作成
      # (画面の情報, 表示領域の情報, 方向の情報) を取得
      (screen, area, orientation) = self.tray.get_geometry()
      print "x:%d y:%d width:%d height:%d\n" % (area.x, area.y, area.width, area.height)
      # ポップアップウィンドウの作成
      self.win = gtk.Window(gtk.WINDOW_POPUP)
      # ドックウィンドウにする場合
#      self.win.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
      if area.x + area.width * (1 + 5) > screen.get_width() or area.x < area.width:
        # 画面右端にある場合は左に表示する
        # アイコンのX座標 + 幅 + (幅 x 5)
        # つまり「アイコンのX座標 + 幅 x (1 + 5)」を画面幅と比較
        if area.x + area.width * (1 + 5) > screen.get_width():
          x      = area.x - area.height * 5
          y      = area.y
          width  = area.width * 5
          height = area.height
        # それ以外は右に表示する
        else:
          x      = area.x + area.height
          y      = area.y
          width  = area.width * 5
          height = area.height
      # システムトレイアイコンが横方向に並ぶ場合(パネルが上下端にある場合など)
      else:
        # 画面上端にある場合は下に表示する
        if area.y < area.height * 5:
          x      = area.x
          y      = area.y + area.height
          width  = area.width
          height = area.height * 5
        # それ以外は上に表示する
        else:
          x      = area.x
          y      = area.y - area.height * 5
          width  = area.width
          height = area.height * 5
      # 上で決めたサイズと位置に調整
      self.win.resize(width, height)
      self.win.move(x, y)
      # ウィンドウを表示
      self.win.show_all()
      self.show = True
  def show_menu(self, widget, button, time):
    self.popup(None, None, gtk.status_icon_position_menu, button, time, self.tray)
  def quit_activate(self, widget):
    """
    終了
    """
    gtk.main_quit()

class PyGTKSystrayGeometryTest2:
  """
  システムトレイのアイコンジオメトリテスト
  """
  def main(self):
    tray = gtk.StatusIcon()
    menu = TrayMenu(tray)
    tray.set_from_stock(gtk.STOCK_DIALOG_INFO)
    tray.connect("popup-menu", menu.show_menu)
    tray.connect("activate", menu.activate)
    gtk.main()


if __name__ == "__main__":
  app = PyGTKSystrayGeometryTest2()
  app.main()

関連記事:

参考URL:

使用したバージョン: