home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / gui / imwin / imtabs.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  25.2 KB  |  705 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. from wx import PyDeadObjectError
  6.  
  7. try:
  8.     _
  9. except:
  10.     import gettext
  11.     gettext.install('Digsby')
  12.  
  13. import wx
  14. import hooks
  15. from wx.lib import pubsub
  16. import config
  17. from gui import skin
  18. from gui.uberwidgets.uberbook.tabmanager import TabWindowManager
  19. from gui.uberwidgets.uberbook.UberBook import NoteBook
  20. from gui.toolbox import draw_tiny_text
  21. from PIL import Image
  22. from gui.windowfx import fadein
  23. from common import setpref, pref, profile, bind, prefprop
  24. from util import traceguard, default_timer
  25. from util.primitives.structures import oset
  26. from util.primitives.funcs import Delegate
  27. from gui.uberwidgets.UberEvents import EVT_TAB_NOTIFIED
  28. from gui.toolbox import saveWindowPos, preLoadWindowPos, snap_pref
  29. from gui.native import memory_event
  30. IMWIN_STAT_IDLE_TIME = 5 * 60 * 1000
  31. CLOSETABS_TITLE = _('Close IM Window')
  32. CHECKBOX_TEXT = _('Warn me when I attempt to close multiple conversations')
  33. CLOSETABS_MSG = _('You are about to close %d conversations.  Are you sure you want to continue?')
  34. CLOSE_BUTTON_TEXT = _('Close &tabs')
  35. WARN_PREF = 'messaging.tabs.warn_on_close'
  36. IMWIN_ALWAYS_ON_TOP_PREF = 'conversation_window.always_on_top'
  37.  
  38. def explodeAllWindows():
  39.     ImFrame = ImFrame
  40.     import gui.imwin.imtabs
  41.     newtabs = 0
  42.     for win in (lambda .0: for w in .0:
  43. if isinstance(w, ImFrame):
  44. wcontinue)(wx.GetTopLevelWindows()):
  45.         for page in win.notebook.Pages()[1:]:
  46.             newtabs += 1
  47.             win.notebook.Remove(page)
  48.             page.tab.Close()
  49.             pos = wx.Point(30, 30) + (20 * newtabs, 20 * newtabs)
  50.             newwin = win.notebook.winman.NewWindow(pos)
  51.             newwin.notebook.Insert(page, False)
  52.         
  53.     
  54.  
  55.  
  56. class CloseTabsDialog(wx.Dialog):
  57.     
  58.     def WarnMe(self):
  59.         return self.panel.warn_cb.Value
  60.  
  61.     WarnMe = property(WarnMe)
  62.     
  63.     def __init__(self, parent, num_tabs, warn_value = True):
  64.         wx.Dialog.__init__(self, parent, title = CLOSETABS_TITLE)
  65.         self.panel = CloseTabsPanel(self, num_tabs, warn_value)
  66.         self.Sizer = wx.BoxSizer(wx.VERTICAL)
  67.         self.Sizer.Add(self.panel, 1, wx.EXPAND)
  68.         self.Fit()
  69.  
  70.  
  71.  
  72. class CloseTabsPanel(wx.Panel):
  73.     
  74.     def __init__(self, parent, num_tabs, warnme_value = True):
  75.         wx.Panel.__init__(self, parent)
  76.         self.Bind(wx.EVT_PAINT, self.OnPaint)
  77.         self.warn_cb = warn_cb = wx.CheckBox(self, -1, CHECKBOX_TEXT)
  78.         warn_cb.SetValue(warnme_value)
  79.         msgsizer = wx.BoxSizer(wx.VERTICAL)
  80.         self.close_msg = wx.StaticText(self, -1, CLOSETABS_MSG % num_tabs)
  81.         msgsizer.Add(self.close_msg, 0, wx.EXPAND | wx.SOUTH, 8)
  82.         msgsizer.Add(warn_cb, 0, wx.EXPAND)
  83.         h = wx.BoxSizer(wx.HORIZONTAL)
  84.         self.bitmap = wx.ArtProvider.GetBitmap(wx.ART_QUESTION)
  85.         self.bitmap.SetMaskColour(wx.BLACK)
  86.         h.Add((self.bitmap.Width, self.bitmap.Height), 0, wx.EXPAND | wx.ALL, 9)
  87.         h.Add(msgsizer, 0, wx.EXPAND | wx.ALL, 12)
  88.         close_button = wx.Button(self, wx.ID_OK, CLOSE_BUTTON_TEXT)
  89.         close_button.SetDefault()
  90.         close_button.SetFocus()
  91.         cancel_button = wx.Button(self, wx.ID_CANCEL, _('&Cancel'))
  92.         buttonsizer = wx.BoxSizer(wx.HORIZONTAL)
  93.         buttonsizer.AddStretchSpacer(1)
  94.         buttonsizer.Add(close_button, 0, wx.RIGHT, 6)
  95.         buttonsizer.Add(cancel_button)
  96.         buttonsizer.AddStretchSpacer(1)
  97.         s = self.Sizer = wx.BoxSizer(wx.VERTICAL)
  98.         s.Add(h, 0, wx.EXPAND | wx.ALL)
  99.         s.Add(buttonsizer, 0, wx.EXPAND | wx.BOTTOM, 12)
  100.  
  101.     
  102.     def OnPaint(self, e):
  103.         dc = wx.PaintDC(self)
  104.         pos = self.close_msg.Position
  105.         dc.DrawBitmap(self.bitmap, pos.x - self.bitmap.Width - 10, pos.y, True)
  106.  
  107.  
  108. from gui.native.toplevel import FlashOnce, Flash
  109.  
  110. class TitleBarTimer(wx.Timer):
  111.     shouldFlash = prefprop('conversation_window.notify_flash')
  112.     cyclePause = prefprop('conversation_window.unread_cycle_pause')
  113.     
  114.     def __init__(self, win, tabs):
  115.         wx.Timer.__init__(self)
  116.         self.win = win
  117.         self.tabs = tabs
  118.         self.index = 0
  119.  
  120.     
  121.     def Start(self):
  122.         self.title = self.win.Title
  123.         wx.Timer.Start(self, self.cyclePause)
  124.  
  125.     
  126.     def Notify(self):
  127.         win = self.win
  128.         tabs = self.tabs
  129.         if wx.IsDestroyed(win):
  130.             self.Stop()
  131.             return None
  132.         if not win.IsActive() and len(tabs):
  133.             tabNum = len(tabs)
  134.             if self.index >= tabNum:
  135.                 self.index = 0
  136.             
  137.             tab = tabs[self.index]
  138.             if not wx.IsDestroyed(tab):
  139.                 win.SetTitle('*' + tab.label1)
  140.                 self.index += 1
  141.             else:
  142.                 tabs.remove(tab)
  143.             if self.shouldFlash:
  144.                 FlashOnce(win)
  145.             
  146.         else:
  147.             self.Stop()
  148.  
  149.     
  150.     def Stop(self):
  151.         wx.Timer.Stop(self)
  152.         if not wx.IsDestroyed(self.win):
  153.             self.win.SetTitle(self.title)
  154.         
  155.         self.index = 0
  156.  
  157.  
  158.  
  159. class SkinnedNotebookPanel(wx.Panel):
  160.     
  161.     def __init__(self, *args, **kwargs):
  162.         preview = kwargs.pop('preview', None)
  163.         wx.Panel.__init__(self, *args, **kwargs)
  164.         self.notebook = NoteBook(self, skinkey = 'Tabs', preview = preview)
  165.         sz = self.Sizer = wx.BoxSizer(wx.VERTICAL)
  166.         sz.Add(self.notebook, 1, wx.EXPAND)
  167.  
  168.  
  169.  
  170. class SkinnedIMFrameEventHandler(wx.EvtHandler):
  171.     
  172.     def __init__(self, frame):
  173.         wx.EvtHandler.__init__(self)
  174.         self.frame = frame
  175.         self.notebook = self.frame.notebookPanel.notebook
  176.         self.mergetimer = None
  177.         self.notifiedtabs = oset()
  178.         self.titletimer = TitleBarTimer(self.frame, self.notifiedtabs)
  179.         self.BindEventsToFrame()
  180.  
  181.     
  182.     def BindEventsToFrame(self):
  183.         Bind = self.frame.Bind
  184.         Bind(wx.EVT_CLOSE, self.OnClose)
  185.         Bind(wx.EVT_MOVE, self.OnMove)
  186.         Bind(wx.EVT_SIZE, self.OnSize)
  187.         Bind(wx.EVT_ACTIVATE, self.OnActivate)
  188.         Bind(EVT_TAB_NOTIFIED, self.OnTabNotify)
  189.         publisher = pubsub.Publisher()
  190.         publisher.subscribe(self.OnPageTitleUpdated, 'tab.title.updated')
  191.         publisher.subscribe(self.OnPageIconUpdated, 'tab.icon.updated')
  192.  
  193.     
  194.     def OnClose(self, event):
  195.         if self.frame.CloseAndSaveState(event):
  196.             self.frame.Destroy()
  197.         else:
  198.             event.Veto()
  199.  
  200.     
  201.     def OnActivate(self, e):
  202.         e.Skip()
  203.         if e.GetActive():
  204.             tab = self.notebook.ActiveTab
  205.             if tab is not None:
  206.                 tab.SetNotify(False)
  207.                 tab.page.Content.FocusTextCtrl()
  208.             
  209.         
  210.         if self.titletimer.IsRunning():
  211.             self.titletimer.Stop()
  212.         
  213.  
  214.     
  215.     def OnPageIconUpdated(self, message):
  216.         (page, icon) = message.data
  217.         if not (self.frame) or wx.IsDestroyed(self.frame):
  218.             return None
  219.         for mypage in self.frame.notebook.Pages():
  220.             if mypage == page and self.frame.notebook.ActiveTab == mypage.tab:
  221.                 self.frame.SetFrameIcon(icon)
  222.                 continue
  223.             wx.IsDestroyed(self.frame)
  224.         
  225.  
  226.     
  227.     def OnPageTitleUpdated(self, message):
  228.         if not (self.frame) or wx.IsDestroyed(self.frame):
  229.             return None
  230.         (imwin, title, window_title) = message.data
  231.         imwin.SetName(title)
  232.         page = None
  233.         for mypage in self.frame.notebook.Pages():
  234.             if mypage.Content is imwin:
  235.                 page = mypage
  236.                 continue
  237.             wx.IsDestroyed(self.frame)
  238.         
  239.         if page is None or page.tab is not self.frame.notebook.ActiveTab:
  240.             return None
  241.         if window_title is not None:
  242.             frame_title = window_title
  243.         else:
  244.             frame_title = title
  245.         if self.titletimer.IsRunning():
  246.             self.titletimer.title = frame_title
  247.         else:
  248.             self.frame.SetTitle(frame_title)
  249.  
  250.     flashTime = prefprop('conversation_window.flash_time')
  251.     flashCount = prefprop('conversation_window.flash_count')
  252.     
  253.     def OnTabNotify(self, event):
  254.         tab = event.tab
  255.         if tab.notified:
  256.             self.notifiedtabs.add(tab)
  257.             notify_unread_message_hook()
  258.         elif tab in self.notifiedtabs:
  259.             self.notifiedtabs.remove(tab)
  260.             notify_unread_message_hook()
  261.             return None
  262.         return None
  263.         if not self.frame.cycleTitle:
  264.             if self.frame.shouldFlash:
  265.                 Flash(self.frame, timeout = self.flashTime, count = self.flashCount)
  266.             
  267.             return None
  268.         if len(self.notifiedtabs) and not self.frame.IsActive():
  269.             if not self.titletimer.IsRunning():
  270.                 self.titletimer.Start()
  271.             
  272.         elif self.titletimer.IsRunning():
  273.             self.titletimer.Stop()
  274.         
  275.  
  276.     
  277.     def OnMove(self, event):
  278.         event.Skip(True)
  279.         if pref('messaging.tabs.enabled', True):
  280.             mt = self.mergetimer
  281.             if mt is None:
  282.                 self.mergetimer = wx.CallLater(10, self.notebook.StartWindowDrag)
  283.             else:
  284.                 mt.Start(10)
  285.         
  286.         event.Skip(True)
  287.  
  288.     
  289.     def OnSize(self, event):
  290.         mt = self.mergetimer
  291.         if mt is not None:
  292.             mt.Stop()
  293.         
  294.         event.Skip(True)
  295.  
  296.  
  297. highlight_color = wx.Color(255, 214, 72)
  298. _highlight_bitmap = None
  299.  
  300. def get_highlight_bitmap():
  301.     global _highlight_bitmap
  302.     if _highlight_bitmap is None:
  303.         import PIL.Image as PIL
  304.         _highlight_bitmap = PIL.Image.new('RGBA', (5, 5), (226, 214, 139, 255)).WXB
  305.     
  306.     return _highlight_bitmap
  307.  
  308. if config.platform == 'win':
  309.     from gui.uberwidgets.uberbook.UberBook import UberBookTabController
  310.     from gui.buddylist.renderers import get_buddy_icon
  311.     
  312.     def icon_for_tab(tab, width, height):
  313.         window = tab.Window
  314.         if window.ischat:
  315.             return skin.get('actionsbar.icons.roomlist')
  316.         buddy = window.Buddy
  317.         notified = window.Tab.notified
  318.         icon = get_buddy_icon(buddy, size = height, round_size = 0, grey_offline = True, meta_lookup = True)
  319.         return icon.WXB
  320.  
  321.     
  322.     class ImTabController(UberBookTabController):
  323.         
  324.         def GetSmallIcon(self, tab):
  325.             bitmap = im_badge(tab.Window)
  326.             window = tab.Window
  327.             if not (window.ischat) and bitmap is None:
  328.                 bitmap = skin.get('statusicons.' + tab.Window.Buddy.status_orb, None).Resized((16, 16))
  329.             elif window.ischat:
  330.                 bitmap = window.chat_icon
  331.             
  332.             if bitmap is not None:
  333.                 return wx.IconFromBitmap(bitmap.WXB)
  334.             return wx.IconFromBitmap(wx.NullBitmap)
  335.  
  336.         
  337.         def GetIconicHBITMAP(self, tab, width, height):
  338.             import cgui
  339.             icon = icon_for_tab(tab, width, height)
  340.             notified = tab.Window.Tab.notified
  341.             highlight = None if notified else wx.NullBitmap
  342.             if icon is not None:
  343.                 return cgui.getBuddyPreview((width, height), icon, highlight)
  344.  
  345.         
  346.         def GetLivePreview(self, tab, rect):
  347.             overlay = skin.get('AppDefaults.TaskBarIcon')
  348.             bitmap = wx.EmptyBitmap(rect.width, rect.height, False)
  349.             dc = wx.MemoryDC(bitmap)
  350.             overlay.Resized(1).Draw(dc, wx.Rect(0, 0, 1, 1))
  351.             dc.SelectObject(wx.NullBitmap)
  352.             return bitmap
  353.  
  354.  
  355.  
  356.  
  357. class ImFrame(wx.Frame):
  358.     WindowName = u'IM Window'
  359.     
  360.     def __init__(self, pos = None, size = None, startMinimized = False, posId = ''):
  361.         if pref('imwin.ads', type = bool, default = False):
  362.             defaultSize = wx.Size(490, 470)
  363.         else:
  364.             defaultSize = wx.Size(470, 390)
  365.         (wininfo, placement) = preLoadWindowPos(ImFrame.WindowName, uniqueId = posId, defaultPos = wx.Point(200, 200), defaultSize = defaultSize)
  366.         wininfo['style'] |= wx.DEFAULT_FRAME_STYLE
  367.         setPos = pos is not None
  368.         setSize = size is not None
  369.         if setPos or setSize:
  370.             wininfo['style'] &= ~(wx.MAXIMIZE)
  371.         
  372.         if startMinimized:
  373.             wininfo['style'] |= wx.ICONIZE
  374.             self._starting_minimized = True
  375.         
  376.         wininfo['style'] |= wx.FULL_REPAINT_ON_RESIZE
  377.         wx.Frame.__init__(self, parent = None, name = ImFrame.WindowName, **wininfo)
  378.         self.on_engaged_start = Delegate()
  379.         self.on_engaged_end = Delegate()
  380.         self.on_sent_message = Delegate()
  381.         if config.nativeIMWindow:
  382.             import gui.imwin.imwin_native as gui
  383.             self.notebookPanel = gui.imwin.imwin_native.NativeNotebookPanel(self, -1)
  384.             self.eventHandler = gui.imwin.imwin_native.NativeIMFrameEventHandler(self)
  385.         else:
  386.             preview = None
  387.             if config.platform == 'win':
  388.                 preview = ImTabController
  389.             
  390.             self.notebookPanel = SkinnedNotebookPanel(self, -1, preview = preview)
  391.             self.eventHandler = SkinnedIMFrameEventHandler(self)
  392.         construct_ad_panel = construct_ad_panel
  393.         import gui.imwin.imwin_ads
  394.         ad_panel = construct_ad_panel(self, self.notebookPanel, self.notebookPanel.notebook.did_add)
  395.         self.notebook.winman = TabWindowManager((lambda pos, size = None: ImFrame(pos = pos, size = size)))
  396.         if placement is not None:
  397.             if not setPos:
  398.                 pass
  399.         if setPos:
  400.             self.Position = pos
  401.         
  402.         if setSize:
  403.             self.Size = size
  404.         
  405.         if not config.nativeIMWindow:
  406.             self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  407.         
  408.         self.posId = posId
  409.         self.EnsureInScreen()
  410.         if pos is not None:
  411.             wx.CallAfter(self.EnsureNotStacked)
  412.         
  413.         profile.prefs.link(IMWIN_ALWAYS_ON_TOP_PREF, self.on_always_on_top, callnow = not startMinimized)
  414.         snap_pref(self)
  415.         self.iconizecallbacks = set()
  416.         Bind = self.Bind
  417.         Bind(wx.EVT_ICONIZE, self.OnIconize)
  418.         memory_event()
  419.         
  420.         def gainfocus(e):
  421.             if e.Active:
  422.                 self._startengage()
  423.             else:
  424.                 self._endengage()
  425.             e.Skip()
  426.  
  427.         Bind(wx.EVT_ACTIVATE, gainfocus)
  428.         self.register_hooks()
  429.  
  430.     
  431.     def register_hooks(self):
  432.         if getattr(ImFrame, 'did_register_hooks', False):
  433.             return None
  434.         ImFrame.did_register_hooks = True
  435.         ImFrame.engage_is_idle = False
  436.         
  437.         def goidle():
  438.             ImFrame.engage_is_idle = True
  439.             for win in all_imframes():
  440.                 win._endengage()
  441.             
  442.             return True
  443.  
  444.         
  445.         def unidle():
  446.             ImFrame.engage_is_idle = False
  447.             for win in all_imframes():
  448.                 if win.IsActive():
  449.                     win._startengage()
  450.                     continue
  451.             
  452.             return True
  453.  
  454.         
  455.         def idle_ms(ms_idle_time):
  456.             if not (ImFrame.engage_is_idle) and ms_idle_time > IMWIN_STAT_IDLE_TIME:
  457.                 goidle()
  458.             elif ImFrame.engage_is_idle and ms_idle_time < IMWIN_STAT_IDLE_TIME:
  459.                 unidle()
  460.             
  461.             return 15000
  462.  
  463.         hooks.register('digsby.app.idle', idle_ms)
  464.         import cgui
  465.         if config.platform == 'win' and cgui.isWin7OrHigher():
  466.             set_overlay_icon = set_overlay_icon
  467.             get_tab_notebook = get_tab_notebook
  468.             import gui.native.win.taskbar
  469.             
  470.             def icon_updated(imwin):
  471.                 get_tab_notebook(imwin.Top).InvalidateThumbnails(imwin)
  472.                 
  473.                 def later():
  474.                     if wx.IsDestroyed(imwin):
  475.                         return None
  476.                     set_overlay_icon(im_badge(), tlw = imwin.Top)
  477.  
  478.                 wx.CallLater(300, later)
  479.  
  480.             hooks.register('digsby.overlay_icon_updated', icon_updated)
  481.         
  482.  
  483.     
  484.     def _startengage(self):
  485.         self._endengage()
  486.         self.start_time = default_timer()
  487.         self.on_engaged_start()
  488.  
  489.     
  490.     def _endengage(self):
  491.         if hasattr(self, 'start_time'):
  492.             diff = max(int(default_timer() - self.start_time), 0)
  493.             del self.start_time
  494.             hooks.notify('digsby.statistics.imwin.imwin_engage', diff)
  495.             self.on_engaged_end()
  496.         
  497.  
  498.     cycleTitle = prefprop('conversation_window.cycle_unread_ims')
  499.     shouldFlash = prefprop('conversation_window.notify_flash')
  500.     
  501.     def OnIconize(self, event = None):
  502.         self._didoniconize = True
  503.         if event is not None:
  504.             event.Skip()
  505.         
  506.         if event is not None and not event.Iconized() and not (self.OnTop) and pref(IMWIN_ALWAYS_ON_TOP_PREF, False):
  507.             self.OnTop = True
  508.         
  509.         for callback in set(self.iconizecallbacks):
  510.             
  511.             try:
  512.                 callback()
  513.             continue
  514.             except PyDeadObjectError:
  515.                 self.iconizecallbacks.remove(callback)
  516.                 continue
  517.             
  518.  
  519.         
  520.  
  521.     
  522.     def notebook(self):
  523.         if hasattr(self, 'notebookPanel') and self.notebookPanel:
  524.             return self.notebookPanel.notebook
  525.  
  526.     notebook = property(notebook)
  527.     
  528.     def AnyNotified(self):
  529.         return any((lambda .0: for iwin in .0:
  530. iwin.Tab.notified)(self))
  531.  
  532.     AnyNotified = property(AnyNotified)
  533.     
  534.     def __iter__(self):
  535.         if config.nativeIMWindow:
  536.             pass
  537.         
  538.         return iter((lambda .0: for p in .0:
  539. p.Content)(self.notebook.Pages()))
  540.  
  541.     
  542.     def __getitem__(self, n):
  543.         if config.nativeIMWindow:
  544.             pass
  545.         
  546.         return self.notebook.Pages()[n].Content
  547.  
  548.     
  549.     def GetTabCount(self):
  550.         return self.notebook.GetTabCount()
  551.  
  552.     
  553.     def AddTab(self, ctrl, focus = None):
  554.         return self.notebook.Add(ctrl, focus = focus)
  555.  
  556.     
  557.     def CloseTabIfNotLast(self):
  558.         if self.notebook.GetTabCount() > 1:
  559.             tab = self.notebook.ActiveTab
  560.             self.notebook.CloseTab(tab)
  561.         
  562.  
  563.     CloseTabIfNotLast = bind('ImFrame.Tabs.CloseIfNotLast')(CloseTabIfNotLast)
  564.     
  565.     def CloseActiveTab(self):
  566.         tab = self.notebook.ActiveTab
  567.         self.notebook.CloseTab(tab)
  568.         if self.notebook.GetTabCount() < 1:
  569.             self.Close()
  570.         
  571.  
  572.     CloseActiveTab = bind('ImFrame.Tabs.CloseActive')(CloseActiveTab)
  573.     
  574.     def NextTab(self):
  575.         self.notebook.NextTab()
  576.  
  577.     NextTab = bind('ImFrame.Tabs.NextTab')(NextTab)
  578.     
  579.     def PrevTab(self):
  580.         self.notebook.PrevTab()
  581.  
  582.     PrevTab = bind('ImFrame.Tabs.PrevTab')(PrevTab)
  583.     
  584.     def IncreaseTextSize(self):
  585.         self.ActiveMessageArea.IncreaseTextSize()
  586.  
  587.     IncreaseTextSize = bind('ImFrame.ChatWindow.IncreaseTextSize')(IncreaseTextSize)
  588.     
  589.     def DescreaseTextSize(self):
  590.         self.ActiveMessageArea.DecreaseTextSize()
  591.  
  592.     DescreaseTextSize = bind('ImFrame.ChatWindow.DecreaseTextSize')(DescreaseTextSize)
  593.     
  594.     def ResetTextSize(self):
  595.         self.ActiveMessageArea.ResetTextSize()
  596.  
  597.     ResetTextSize = bind('ImFrame.ChatWindow.ResetTextSize')(ResetTextSize)
  598.     
  599.     def ActiveMessageArea(self):
  600.         return self.notebook.ActiveTab.page.Content.message_area
  601.  
  602.     ActiveMessageArea = property(ActiveMessageArea)
  603.     
  604.     def CloseAndSaveState(self, e):
  605.         tabcount = self.GetTabCount()
  606.         self.Hide()
  607.         saveWindowPos(self, uniqueId = self.posId)
  608.         if not config.nativeIMWindow:
  609.             for page in self.notebook.Pages():
  610.                 page.Children[0].on_close()
  611.             
  612.         
  613.         memory_event()
  614.         return True
  615.  
  616.     
  617.     def __repr__(self):
  618.         return '<%s %s>' % (self.__class__.__name__, id(self))
  619.  
  620.     
  621.     def on_always_on_top(self, val):
  622.         self.OnTop = val
  623.  
  624.     
  625.     def UpdateSkin(self):
  626.         wx.CallAfter(self.Layout)
  627.  
  628.  
  629.  
  630. def newIMWindow(pos, size):
  631.     win = ImFrame(pos, size)
  632.     win.Show(False)
  633.     fadein(win, 'normal')
  634.     return win
  635.  
  636.  
  637. def all_imframes():
  638.     return _[1]
  639.  
  640.  
  641. def notify_unread_message_hook():
  642.     hooks.notify('digsby.im.unread_messages_changed')
  643.  
  644.  
  645. def all_unread_convos():
  646.     imwins = []
  647.     for imframe in all_imframes():
  648.         imwins.extend((lambda .0: for tab in .0:
  649. tab.page.panel)(imframe.eventHandler.notifiedtabs))
  650.     
  651.     return imwins
  652.  
  653.  
  654. def im_badge(specific_page = None):
  655.     imwins = []
  656.     typing_statuses = dict((lambda .0: for i, s in .0:
  657. (s, i))(enumerate([
  658.         None,
  659.         'typed',
  660.         'typing'])))
  661.     max_typing = None
  662.     unread_count = 0
  663.     needs_bubbles = False
  664.     if specific_page is None:
  665.         for imframe in all_imframes():
  666.             notified_wins = set((lambda .0: for tab in .0:
  667. tab.page.panel)(imframe.eventHandler.notifiedtabs))
  668.             for page in imframe.notebook.Pages():
  669.                 imwin = page.panel
  670.                 if typing_statuses[imwin.typing] > typing_statuses[max_typing]:
  671.                     max_typing = imwin.typing
  672.                 
  673.                 if imwin in notified_wins:
  674.                     unread_count += 1
  675.                     continue
  676.             
  677.         
  678.     else:
  679.         max_typing = specific_page.typing
  680.         needs_bubbles = specific_page.Notified
  681.     bubble_icon = None
  682.     if max_typing is not None:
  683.         bubble_icon = skin.get('statusicons.' + max_typing, None)
  684.     
  685.     if bubble_icon is None:
  686.         if (unread_count or specific_page is not None) and needs_bubbles:
  687.             bubble_icon = skin.get('AppDefaults.UnreadMessageIcon', None)
  688.         
  689.     if bubble_icon is not None:
  690.         bubble_icon = bubble_icon.PIL.ResizeCanvas(16, 16)
  691.     
  692.     if unread_count:
  693.         if bubble_icon is None:
  694.             bubble_icon = Image.new('RGBA', (16, 16))
  695.         
  696.         bubble_icon = draw_tiny_text(bubble_icon, str(unread_count))
  697.     
  698.     if specific_page is None and bubble_icon is not None:
  699.         bubble_icon = bubble_icon.WXB
  700.     
  701.     return bubble_icon
  702.  
  703. from gui.input import add_class_context
  704. add_class_context(_('IM Windows'), 'ImFrame', cls = ImFrame)
  705.