From cc745f990ff2d53eb3e448353d0b013eeb929b1a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 7 Aug 2007 17:56:14 -0400 Subject: [PATCH 01/13] DevConsole: Fix broken procfs parser --- .../memphis/plugins/memphis_init/info.py | 1 + services/console/lib/procmem/proc.py | 47 ++++++++++++------- services/console/lib/procmem/proc_smaps.py | 4 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/services/console/interface/memphis/plugins/memphis_init/info.py b/services/console/interface/memphis/plugins/memphis_init/info.py index 6e524c72..667645c5 100644 --- a/services/console/interface/memphis/plugins/memphis_init/info.py +++ b/services/console/interface/memphis/plugins/memphis_init/info.py @@ -11,3 +11,4 @@ def plg_on_top_data_refresh(self, ppinfo): data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']] return data + diff --git a/services/console/lib/procmem/proc.py b/services/console/lib/procmem/proc.py index adc2f6b9..d50242be 100644 --- a/services/console/lib/procmem/proc.py +++ b/services/console/lib/procmem/proc.py @@ -1,4 +1,6 @@ -import sys, os +import os +import re +import sys import string class ProcInfo: @@ -36,10 +38,12 @@ class ProcInfo: return None # Parsing data , check 'man 5 proc' for details - data = infile.read().split() - + stat_data = infile.read() infile.close() - + + process_name = self._get_process_name(stat_data) + data = self._get_safe_split(stat_data) + state_dic = { 'R': 'Running', 'S': 'Sleeping', @@ -48,27 +52,34 @@ class ProcInfo: 'T': 'Traced/Stopped', 'W': 'Paging' } - + # user and group owners pidstat = os.stat(pidfile) - info = { - 'pid': int(data[0]), # Process ID - 'name': data[1].strip('()'), # Process name - 'state': data[2], # Process State, ex: R|S|D|Z|T|W - 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc - 'ppid': int(data[3]), # Parent process ID - 'utime': int(data[13]), # Used jiffies in user mode - 'stime': int(data[14]), # Used jiffies in kernel mode - 'start_time': int(data[21]), # Process time from system boot (jiffies) - 'vsize': int(data[22]), # Virtual memory size used (bytes) - 'rss': int(data[23])*4, # Resident Set Size (bytes) + 'pid': int(data[0]), # Process ID + 'name': process_name, + 'state': data[2], # Process State, ex: R|S|D|Z|T|W + 'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc + 'ppid': int(data[3]), # Parent process ID + 'utime': int(data[13]), # Used jiffies in user mode + 'stime': int(data[14]), # Used jiffies in kernel mode + 'start_time': int(data[21]), # Process time from system boot (jiffies) + 'vsize': int(data[22]), # Virtual memory size used (bytes) + 'rss': int(data[23])*4, # Resident Set Size (bytes) 'user_id': pidstat.st_uid, # process owner 'group_id': pidstat.st_gid # owner group } - + return info - + + # Return the process name + def _get_process_name(self, data): + m = re.search("\(.*\)", data) + return m.string[m.start()+1:m.end()-1] + + def _get_safe_split(self, data): + new_data = re.sub("\(.*\)", '()', data) + return new_data.split() # Returns the CPU usage expressed in Jiffies def get_CPU_usage(self, cpu_hz, used_jiffies, start_time): diff --git a/services/console/lib/procmem/proc_smaps.py b/services/console/lib/procmem/proc_smaps.py index ce93cb21..174bc6be 100644 --- a/services/console/lib/procmem/proc_smaps.py +++ b/services/console/lib/procmem/proc_smaps.py @@ -56,8 +56,8 @@ class ProcSmaps: mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name) self.mappings.append (mapping) - num_lines -= 7 - line_idx += 7 + num_lines -= 8 + line_idx += 8 # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field def parse_smaps_size_line (self, line): From a3efc1284f44b3305c2310ecf4ee4aeb7b4d498c Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 7 Aug 2007 17:59:38 -0400 Subject: [PATCH 02/13] DevConsole: Fix Memphis start/stop button --- services/console/interface/memphis/memphis.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/console/interface/memphis/memphis.py b/services/console/interface/memphis/memphis.py index 0dd52fcd..5b1ce405 100644 --- a/services/console/interface/memphis/memphis.py +++ b/services/console/interface/memphis/memphis.py @@ -130,15 +130,14 @@ class Data: treeview.set_model(self.store) def _start_memphis(self, button): - # Update information every 1.5 second button.hide() self.interface.button_stop.show() self._running_status = True - gobject.timeout_add(1500, self.load_data, self.treeview) + self._gid = gobject.timeout_add(1500, self.load_data, self.treeview) def _stop_memphis(self, button): - + gobject.source_remove(self._gid) self._running_status = False button.hide() self.interface.button_start.show() From 91f68897a61fb6180fcb7cfba76bd3cc0c87be30 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 7 Aug 2007 18:14:19 -0400 Subject: [PATCH 03/13] DevConsole: New referenced memory usage field in Memphis (introduced in kernel 2.6.22) --- .../memphis/plugins/dirty_size/__init__.py | 17 ---------------- .../plugins/{dirty_size => smaps}/Makefile.am | 0 .../plugins/{dirty_size => smaps}/README | 0 .../memphis/plugins/smaps/__init__.py | 17 ++++++++++++++++ .../plugins/{dirty_size => smaps}/info.py | 11 +++++----- services/console/lib/procmem/analysis.py | 20 ++++++++++--------- services/console/lib/procmem/proc_smaps.py | 16 ++++++++++++--- 7 files changed, 46 insertions(+), 35 deletions(-) delete mode 100644 services/console/interface/memphis/plugins/dirty_size/__init__.py rename services/console/interface/memphis/plugins/{dirty_size => smaps}/Makefile.am (100%) rename services/console/interface/memphis/plugins/{dirty_size => smaps}/README (100%) create mode 100644 services/console/interface/memphis/plugins/smaps/__init__.py rename services/console/interface/memphis/plugins/{dirty_size => smaps}/info.py (68%) diff --git a/services/console/interface/memphis/plugins/dirty_size/__init__.py b/services/console/interface/memphis/plugins/dirty_size/__init__.py deleted file mode 100644 index f8e9e0a7..00000000 --- a/services/console/interface/memphis/plugins/dirty_size/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ - -import info - - -INTERNALS = { - # Basic information - 'PLGNAME': "Dirty Size", - 'TABNAME': None, # No tabbed plugin - 'AUTHOR': "Eduardo Silva", - 'DESC': "Get dirty size memory usage", - - # Plugin API - 'Plg': None, # Plugin object - - 'top_data': [int], # Top data types needed by memphis core plugin - 'top_cols': ["PDRSS (kb)"] - } diff --git a/services/console/interface/memphis/plugins/dirty_size/Makefile.am b/services/console/interface/memphis/plugins/smaps/Makefile.am similarity index 100% rename from services/console/interface/memphis/plugins/dirty_size/Makefile.am rename to services/console/interface/memphis/plugins/smaps/Makefile.am diff --git a/services/console/interface/memphis/plugins/dirty_size/README b/services/console/interface/memphis/plugins/smaps/README similarity index 100% rename from services/console/interface/memphis/plugins/dirty_size/README rename to services/console/interface/memphis/plugins/smaps/README diff --git a/services/console/interface/memphis/plugins/smaps/__init__.py b/services/console/interface/memphis/plugins/smaps/__init__.py new file mode 100644 index 00000000..5977d4bd --- /dev/null +++ b/services/console/interface/memphis/plugins/smaps/__init__.py @@ -0,0 +1,17 @@ + +import info + + +INTERNALS = { + # Basic information + 'PLGNAME': "SMaps", + 'TABNAME': None, # No tabbed plugin + 'AUTHOR': "Eduardo Silva", + 'DESC': "Get dirty size and reference memory usage", + + # Plugin API + 'Plg': None, # Plugin object + + 'top_data': [int, int], # Top data types needed by memphis core plugin + 'top_cols': ["PDRSS (kb)", "Referenced (kb)"] + } diff --git a/services/console/interface/memphis/plugins/dirty_size/info.py b/services/console/interface/memphis/plugins/smaps/info.py similarity index 68% rename from services/console/interface/memphis/plugins/dirty_size/info.py rename to services/console/interface/memphis/plugins/smaps/info.py index 54a2e7e7..998a1a25 100644 --- a/services/console/interface/memphis/plugins/dirty_size/info.py +++ b/services/console/interface/memphis/plugins/smaps/info.py @@ -8,13 +8,12 @@ def plg_on_top_data_refresh(self, ppinfo): - - dirty_sizes = get_dirty(self, ppinfo['pid']) + smaps = get_data(self, ppinfo['pid']) - # memhis need an array - return [dirty_sizes['private']] + # memphis need an array + return [smaps['private_dirty'], smaps['referenced']] -def get_dirty(pself, pid): +def get_data(pself, pid): ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid) - return ProcAnalysis.DirtyRSS() + return ProcAnalysis.SMaps() diff --git a/services/console/lib/procmem/analysis.py b/services/console/lib/procmem/analysis.py index d2a247a6..e9d7aec8 100644 --- a/services/console/lib/procmem/analysis.py +++ b/services/console/lib/procmem/analysis.py @@ -7,20 +7,22 @@ class Analysis: def __init__(self, pid): self.pid = pid - def DirtyRSS(self): + def SMaps(self): smaps = proc_smaps.ProcSmaps(self.pid) - dirty = [] + private_dirty = 0 + shared_dirty = 0 + referenced = 0 - private = 0 - shared = 0 - for map in smaps.mappings: - private += map.private_dirty - shared += map.shared_dirty + private_dirty += map.private_dirty + shared_dirty += map.shared_dirty + referenced += map.referenced - dirty = {"private": int(private), "shared": int(shared)} + smaps = {"private_dirty": int(private_dirty), \ + "shared_dirty": int(shared_dirty),\ + "referenced": int(referenced)} - return dirty + return smaps def ApproxRealMemoryUsage(self): maps = proc_smaps.ProcMaps(self.pid) diff --git a/services/console/lib/procmem/proc_smaps.py b/services/console/lib/procmem/proc_smaps.py index 174bc6be..422866cc 100644 --- a/services/console/lib/procmem/proc_smaps.py +++ b/services/console/lib/procmem/proc_smaps.py @@ -36,7 +36,8 @@ class ProcSmaps: # Shared_Dirty: 0 kB # Private_Clean: 8 kB # Private_Dirty: 0 kB - + # Referenced: 4 kb -> Introduced in kernel 2.6.22 + while num_lines > 0: fields = lines[line_idx].split (" ", 5) if len (fields) == 6: @@ -51,13 +52,20 @@ class ProcSmaps: shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4]) private_clean = self.parse_smaps_size_line (lines[line_idx + 5]) private_dirty = self.parse_smaps_size_line (lines[line_idx + 6]) + referenced = self.parse_smaps_size_line (lines[line_idx + 7]) name = name.strip () - mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name) + mapping = Mapping (size, rss, shared_clean, shared_dirty, \ + private_clean, private_dirty, referenced, permissions, name) self.mappings.append (mapping) num_lines -= 8 line_idx += 8 + + self._clear_reference(pid) + + def _clear_reference(self, pid): + os.system("echo 1 > /proc/%s/clear_refs" % pid) # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field def parse_smaps_size_line (self, line): @@ -66,13 +74,15 @@ class ProcSmaps: return int(fields[1]) class Mapping: - def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name): + def __init__ (self, size, rss, shared_clean, shared_dirty, \ + private_clean, private_dirty, referenced, permissions, name): self.size = size self.rss = rss self.shared_clean = shared_clean self.shared_dirty = shared_dirty self.private_clean = private_clean self.private_dirty = private_dirty + self.referenced = referenced self.permissions = permissions self.name = name From 26a7e087fad007215f420e6d2a270c9b435483ca Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 7 Aug 2007 18:18:15 -0400 Subject: [PATCH 04/13] DevConsole: ups! fix Makefile.am --- services/console/interface/memphis/plugins/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/console/interface/memphis/plugins/Makefile.am b/services/console/interface/memphis/plugins/Makefile.am index a18eafe7..d026419d 100644 --- a/services/console/interface/memphis/plugins/Makefile.am +++ b/services/console/interface/memphis/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = clean_size cpu dirty_size memphis_init +SUBDIRS = clean_size cpu smaps memphis_init sugardir = $(pkgdatadir)/services/console/interface/memphis/plugins sugar_PYTHON = From 0b355dcbb96a46e496401444377e92577ffd1939 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 03:07:00 +0200 Subject: [PATCH 05/13] First go at support of focusable widgets inside the palette. Not enabled yet because focus confuses our deactivation logic but it seem to work otherwise. --- lib/ui/sugar-menu.c | 43 ++-------- lib/ui/sugar-menu.h | 12 ++- sugar/_sugaruiext.defs | 14 ++-- sugar/_sugaruiext.override | 1 + sugar/graphics/palette.py | 165 ++++++++++++++----------------------- 5 files changed, 82 insertions(+), 153 deletions(-) diff --git a/lib/ui/sugar-menu.c b/lib/ui/sugar-menu.c index 6ed482ee..d822867e 100644 --- a/lib/ui/sugar-menu.c +++ b/lib/ui/sugar-menu.c @@ -28,54 +28,21 @@ static void sugar_menu_init (SugarMenu *menu); G_DEFINE_TYPE(SugarMenu, sugar_menu, GTK_TYPE_MENU) void -sugar_menu_popup(SugarMenu *menu, - int x, - int y) +sugar_menu_set_active(SugarMenu *menu, gboolean active) { - GtkWidget *window; - - window = GTK_MENU(menu)->toplevel; - g_return_if_fail(window != NULL); - - GTK_MENU_SHELL(menu)->active = TRUE; - - gtk_widget_show(GTK_WIDGET(menu)); - - gtk_window_move(GTK_WINDOW(window), x, y); - gtk_widget_show(window); + GTK_MENU_SHELL(menu)->active = active; } void -sugar_menu_popdown(SugarMenu *menu) +sugar_menu_embed(SugarMenu *menu, GtkContainer *parent) { - GtkWidget *window; - - window = GTK_MENU(menu)->toplevel; - g_return_if_fail(window != NULL); - - GTK_MENU_SHELL(menu)->active = FALSE; - - gtk_widget_hide(GTK_WIDGET(menu)); - gtk_widget_hide(window); -} - -static void -sugar_menu_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - SugarMenu *menu = SUGAR_MENU(widget); - - (* GTK_WIDGET_CLASS (sugar_menu_parent_class)->size_request) (widget, requisition); - - requisition->width = MAX(requisition->width, menu->min_width); + GTK_MENU(menu)->toplevel = gtk_widget_get_toplevel(GTK_WIDGET(parent)); + gtk_widget_reparent(GTK_WIDGET(menu), GTK_WIDGET(parent)); } static void sugar_menu_class_init(SugarMenuClass *menu_class) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(menu_class); - - widget_class->size_request = sugar_menu_size_request; } static void diff --git a/lib/ui/sugar-menu.h b/lib/ui/sugar-menu.h index 24e2865b..05e28024 100644 --- a/lib/ui/sugar-menu.h +++ b/lib/ui/sugar-menu.h @@ -44,13 +44,11 @@ struct _SugarMenuClass { GtkMenuClass base_class; }; -GType sugar_menu_get_type (void); -void sugar_menu_popup (SugarMenu *menu, - int x, - int y); -void sugar_menu_set_min_width (SugarMenu *menu, - int min_width); -void sugar_menu_popdown (SugarMenu *menu); +GType sugar_menu_get_type (void); +void sugar_menu_set_active (SugarMenu *menu, + gboolean active); +void sugar_menu_embed (SugarMenu *menu, + GtkContainer *parent); G_END_DECLS diff --git a/sugar/_sugaruiext.defs b/sugar/_sugaruiext.defs index c4efbbc3..456344a1 100644 --- a/sugar/_sugaruiext.defs +++ b/sugar/_sugaruiext.defs @@ -26,20 +26,22 @@ ;; From sugar-menu.h -(define-method popup +(define-method set_active (of-object "SugarMenu") - (c-name "sugar_menu_popup") + (c-name "sugar_menu_set_active") (return-type "none") (parameters - '("gint" "x") - '("gint" "y") + '("gboolean" "active") ) ) -(define-method popdown +(define-method embed (of-object "SugarMenu") - (c-name "sugar_menu_popdown") + (c-name "sugar_menu_embed") (return-type "none") + (parameters + '("GtkContainer" "container") + ) ) ;; From sugar-key-grabber.h diff --git a/sugar/_sugaruiext.override b/sugar/_sugaruiext.override index 02e900ea..6daafc3b 100644 --- a/sugar/_sugaruiext.override +++ b/sugar/_sugaruiext.override @@ -18,6 +18,7 @@ modulename _sugarext import gobject.GObject as PyGObject_Type import gtk.Entry as PyGtkEntry_Type import gtk.Menu as PyGtkMenu_Type +import gtk.Container as PyGtkContainer_Type import gtk.gdk.Window as PyGdkWindow_Type %% ignore-glob diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 45ac0572..8d4c48f3 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -36,7 +36,7 @@ _RIGHT_TOP = 5 _TOP_LEFT = 6 _TOP_RIGHT = 7 -class Palette(gobject.GObject): +class Palette(gtk.Window): DEFAULT = 0 AT_CURSOR = 1 AROUND = 2 @@ -65,12 +65,16 @@ class Palette(gobject.GObject): } def __init__(self, label, accel_path=None): - gobject.GObject.__init__(self) + gtk.Window.__init__(self) + + self.set_decorated(False) + self.set_resizable(False) + self.connect('realize', self._realize_cb) self._full_request = [0, 0] self._cursor_x = 0 self._cursor_y = 0 - self._state = self._SECONDARY + self._state = self._PRIMARY self._invoker = None self._group_id = None self._up = False @@ -86,56 +90,56 @@ class Palette(gobject.GObject): self._popdown_anim = animator.Animator(0.6, 10) self._popdown_anim.add(_PopdownAnimation(self)) + vbox = gtk.VBox() + vbox.set_border_width(style.DEFAULT_PADDING) + + self._label = gtk.Label() + vbox.pack_start(self._label, False) + + self._separator = gtk.HSeparator() + vbox.pack_start(self._separator) + + menu_box = gtk.VBox() + vbox.pack_start(menu_box) + menu_box.show() + self._menu = _sugaruiext.Menu() + self._menu.embed(menu_box) - self._primary = _PrimaryMenuItem(label, accel_path) - self._menu.append(self._primary) - self._primary.show() + self._content = gtk.VBox() + vbox.pack_start(self._content) - self._separator = gtk.SeparatorMenuItem() - self._menu.append(self._separator) + self._button_bar = gtk.HButtonBox() + vbox.pack_start(self._button_bar) - self._content = _ContentMenuItem() - self._menu.append(self._content) + self.add(vbox) + vbox.show() - self._button_bar = _ButtonBarMenuItem() - self._menu.append(self._button_bar) + self.connect('enter-notify-event', + self._enter_notify_event_cb) + self.connect('leave-notify-event', + self._leave_notify_event_cb) - self._menu.connect('enter-notify-event', - self._enter_notify_event_cb) - self._menu.connect('leave-notify-event', - self._leave_notify_event_cb) + self.set_primary_text(label, accel_path) def is_up(self): return self._up def set_primary_text(self, label, accel_path=None): - self._primary.set_label(label, accel_path) + self._label.set_text(label) + self._label.show() def append_menu_item(self, item): - self._separator.show() - self._menu.insert(item, len(self._menu.get_children()) - 2) + self._menu.append(item) def insert_menu_item(self, item, index=-1): - self._separator.show() - if index < 0: - self._menu.insert(item, len(self._menu.get_children()) - 2) - else: - self._menu.insert(item, index + 2) + self._menu.insert(item, index) def remove_menu_item(self, index): - if index > len(self._menu.get_children()) - 4: - raise ValueError('index %i out of range' % index) - self._menu.remove(self._menu.get_children()[index + 2]) - if len(self._menu.get_children()) == 0: - self._separator.hide() + self._menu.remove(self._menu.get_children()[index]) - def menu_item_count(self): - return len(self._menu.get_children()) - 4 - def set_content(self, widget): - self._content.set_widget(widget) - self._content.show() + self._content.pack_start(widget) def append_button(self, button): self._button_bar.append_button(button) @@ -168,6 +172,10 @@ class Palette(gobject.GObject): else: raise AssertionError + def _realize_cb(self, widget): + self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + self.window.set_accept_focus(False) + def _in_screen(self, x, y): [width, height] = self._full_request screen_area = self._invoker.get_screen_area() @@ -182,7 +190,7 @@ class Palette(gobject.GObject): if inv_rect == None: inv_rect = self._invoker.get_rect() - palette_width, palette_height = self._menu.size_request() + palette_width, palette_height = self.size_request() x = inv_rect.x + inv_rect.width * invoker_halign + \ palette_width * palette_halign @@ -241,12 +249,12 @@ class Palette(gobject.GObject): def _update_full_request(self): state = self._state - self._menu.set_size_request(-1, -1) + self.set_size_request(-1, -1) self._set_state(self._SECONDARY) - self._full_request = self._menu.size_request() + self._full_request = self.size_request() - self._menu.set_size_request(self._full_request[0], -1) + self.set_size_request(self._full_request[0], -1) self._set_state(state) @@ -282,7 +290,7 @@ class Palette(gobject.GObject): elif position == self.TOP: x, y = self._get_top_position() - self._menu.popup(x, y) + self.move(x, y) def _show(self): if self._up: @@ -296,6 +304,8 @@ class Palette(gobject.GObject): self._palette_observer_popup_cb) self._update_position() + self._menu.set_active(True) + self.show() self._up = True _palette_observer.emit('popup', self) @@ -305,7 +315,8 @@ class Palette(gobject.GObject): if not self._palette_popup_sid is None: _palette_observer.disconnect(self._palette_popup_sid) self._palette_popup_sid = None - self._menu.popdown() + self._menu.set_active(False) + self.hide() self._up = False self.emit('popdown') @@ -329,25 +340,22 @@ class Palette(gobject.GObject): return if state == self._PRIMARY: - self._primary.show() - for menu_item in self._menu.get_children()[1:]: - menu_item.hide() + self._menu.hide() + self._content.hide() + self._separator.hide() + self._button_bar.hide() elif state == self._SECONDARY: - middle_menu_items = self._menu.get_children() - middle_menu_items = middle_menu_items[2:len(middle_menu_items) - 2] - if middle_menu_items or \ - not self._content.is_empty() or \ - not self._button_bar.is_empty(): - self._separator.show() + has_menu_items = len(self._menu.get_children()) > 0 + self._menu.props.visible = has_menu_items - for menu_item in middle_menu_items: - menu_item.show() + has_content = len(self._content.get_children()) > 0 + self._content.props.visible = has_content - if not self._content.is_empty(): - self._content.show() + has_buttons = len(self._button_bar.get_children()) > 0 + self._button_bar.props.visible = has_buttons - if not self._button_bar.is_empty(): - self._button_bar.show() + has_separator = has_buttons or has_menu_items or has_content + self._separator.props.visible = has_separator self._state = state @@ -373,53 +381,6 @@ class Palette(gobject.GObject): if self != palette: self._hide() -class _PrimaryMenuItem(gtk.MenuItem): - def __init__(self, label, accel_path): - gtk.MenuItem.__init__(self) - self.set_border_width(style.DEFAULT_PADDING) - self._set_label(label, accel_path) - - def set_label(self, label, accel_path): - self.remove(self._label) - self._set_label(label, accel_path) - - def _set_label(self, label, accel_path): - self._label = gtk.AccelLabel(label) - self._label.set_accel_widget(self) - - if accel_path: - self.set_accel_path(accel_path) - self._label.set_alignment(0.0, 0.5) - - self.add(self._label) - self._label.show() - -class _ContentMenuItem(gtk.MenuItem): - def __init__(self): - gtk.MenuItem.__init__(self) - - def set_widget(self, widget): - if self.child: - self.remove(self.child) - self.add(widget) - - def is_empty(self): - return self.child is None or not self.child.props.visible - -class _ButtonBarMenuItem(gtk.MenuItem): - def __init__(self): - gtk.MenuItem.__init__(self) - - self._hbar = gtk.HButtonBox() - self.add(self._hbar) - self._hbar.show() - - def append_button(self, button): - self._hbar.pack_start(button) - - def is_empty(self): - return len(self._hbar.get_children()) == 0 - class _PopupAnimation(animator.Animation): def __init__(self, palette): animator.Animation.__init__(self, 0.0, 1.0) From 8a6ea5b13f9761d259c0b58cb18071ce09f58691 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 8 Aug 2007 10:34:11 +0200 Subject: [PATCH 06/13] Added missing file in configure.ac --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2e7e3399..f6626693 100644 --- a/configure.ac +++ b/configure.ac @@ -64,7 +64,7 @@ services/console/Makefile services/console/interface/Makefile services/console/interface/xo/Makefile services/console/interface/memphis/plugins/clean_size/Makefile -services/console/interface/memphis/plugins/dirty_size/Makefile +services/console/interface/memphis/plugins/smaps/Makefile services/console/interface/memphis/plugins/Makefile services/console/interface/memphis/plugins/memphis_init/Makefile services/console/interface/memphis/plugins/cpu/Makefile From 51ce8abdef7a9af0ebef554e4b2904f45f8d747e Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 8 Aug 2007 10:56:12 +0200 Subject: [PATCH 07/13] Adapt to new color constants. --- shell/view/clipboardicon.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shell/view/clipboardicon.py b/shell/view/clipboardicon.py index a47104d8..2e60e36b 100644 --- a/shell/view/clipboardicon.py +++ b/shell/view/clipboardicon.py @@ -73,9 +73,9 @@ class ClipboardIcon(CanvasIcon): self._selected = selected if selected: if not self._hover: - self.props.background_color = style.COLOR_PANEL_GREY.get_int() + self.props.background_color = style.COLOR_SELECTION_GREY.get_int() else: - self.props.background_color = style.COLOR_TOOLBAR_GREY.get_int() + self.props.background_color = style.COLOR_PANEL_GREY.get_int() def set_state(self, name, percent, icon_name, preview, activity): cb_service = clipboardservice.get_instance() @@ -107,11 +107,11 @@ class ClipboardIcon(CanvasIcon): def prelight(self, enter): if enter: self._hover = True - self.props.background_color = color.BLACK.get_int() + self.props.background_color = style.COLOR_BLACK.get_int() else: self._hover = False if self._selected: - self.props.background_color = color.DESKTOP_BACKGROUND.get_int() + self.props.background_color = style.COLOR_SELECTION_GREY.get_int() else: - self.props.background_color = color.TOOLBAR_BACKGROUND.get_int() + self.props.background_color = style.COLOR_PANEL_GREY.get_int() From 3a33e4cedd8b31afe0856ed76d68cecba535a193 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 11:53:41 +0200 Subject: [PATCH 08/13] Enable focus when there is content. Remove the focus out check on the invoker toplevel, we will have to do that differently. --- sugar/graphics/palette.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 8d4c48f3..0fb7182c 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -139,6 +139,7 @@ class Palette(gtk.Window): self._menu.remove(self._menu.get_children()[index]) def set_content(self, widget): + self._update_accept_focus() self._content.pack_start(widget) def append_button(self, button): @@ -158,7 +159,6 @@ class Palette(gtk.Window): self._invoker = value self._invoker.connect('mouse-enter', self._invoker_mouse_enter_cb) self._invoker.connect('mouse-leave', self._invoker_mouse_leave_cb) - self._invoker.connect('focus-out', self._invoker_focus_out_cb) elif pspec.name == 'position': self._position = value else: @@ -172,9 +172,14 @@ class Palette(gtk.Window): else: raise AssertionError + def _update_accept_focus(self): + accept_focus = len(self._content.get_children()) + if self.window: + self.window.set_accept_focus(accept_focus) + def _realize_cb(self, widget): self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) - self.window.set_accept_focus(False) + self._update_accept_focus() def _in_screen(self, x, y): [width, height] = self._full_request @@ -299,9 +304,8 @@ class Palette(gtk.Window): self._update_cursor_position() self._update_full_request() - self._invoker.connect_to_parent() - self._palette_popup_sid = _palette_observer.connect('popup', - self._palette_observer_popup_cb) + self._palette_popup_sid = _palette_observer.connect( + 'popup', self._palette_observer_popup_cb) self._update_position() self._menu.set_active(True) @@ -365,9 +369,6 @@ class Palette(gtk.Window): def _invoker_mouse_leave_cb(self, invoker): self.popdown() - def _invoker_focus_out_cb(self, invoker): - self._hide() - def _enter_notify_event_cb(self, widget, event): if event.detail == gtk.gdk.NOTIFY_NONLINEAR: self._popdown_anim.stop() @@ -430,13 +431,6 @@ class Invoker(gobject.GObject): height = gtk.gdk.screen_height() return gtk.gdk.Rectangle(0, 0, width, height) - def connect_to_parent(self): - window = self.get_toplevel() - window.connect('focus-out-event', self._window_focus_out_event_cb) - - def _window_focus_out_event_cb(self, widget, event): - self.emit('focus-out') - class WidgetInvoker(Invoker): def __init__(self, widget): Invoker.__init__(self) From 2c0ad08fcfed2dba9677b46118e89c3a614f8316 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 11:53:41 +0200 Subject: [PATCH 09/13] Call embed after the widget hierarchy is setup so that we get the right toplevel. --- sugar/graphics/palette.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 0fb7182c..9d578773 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -103,9 +103,6 @@ class Palette(gtk.Window): vbox.pack_start(menu_box) menu_box.show() - self._menu = _sugaruiext.Menu() - self._menu.embed(menu_box) - self._content = gtk.VBox() vbox.pack_start(self._content) @@ -115,6 +112,9 @@ class Palette(gtk.Window): self.add(vbox) vbox.show() + self._menu = _sugaruiext.Menu() + self._menu.embed(menu_box) + self.connect('enter-notify-event', self._enter_notify_event_cb) self.connect('leave-notify-event', From 6dd6b0275b34ab6aa029427ee33ec59686319f21 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 12:56:19 +0200 Subject: [PATCH 10/13] Expose palette.menu rather than wrapping methods. --- shell/view/BuddyMenu.py | 5 ++- shell/view/home/HomeBox.py | 2 +- shell/view/home/activitiesdonut.py | 4 +- sugar/graphics/palette.py | 72 ++++++++++++++++-------------- 4 files changed, 45 insertions(+), 38 deletions(-) diff --git a/shell/view/BuddyMenu.py b/shell/view/BuddyMenu.py index 3162ab1f..8022b0b3 100644 --- a/shell/view/BuddyMenu.py +++ b/shell/view/BuddyMenu.py @@ -85,7 +85,8 @@ class BuddyMenu(Palette): else: menu_item = MenuItem(_('Make friend'), 'stock-add') menu_item.connect('activate', self._make_friend_cb) - self.append_menu_item(menu_item) + + self.menu.append(menu_item) menu_item.show() activity = shell_model.get_home().get_current_activity() @@ -96,7 +97,7 @@ class BuddyMenu(Palette): menu_item = MenuItem(_('Invite'), 'stock-invite') menu_item.connect('activate', self._invite_friend_cb) - self.append_menu_item(menu_item) + self.menu.append(menu_item) menu_item.show() def _buddy_icon_changed_cb(self, buddy): diff --git a/shell/view/home/HomeBox.py b/shell/view/home/HomeBox.py index bfb4265f..2fa21834 100644 --- a/shell/view/home/HomeBox.py +++ b/shell/view/home/HomeBox.py @@ -130,7 +130,7 @@ class HomeMyIcon(MyIcon): shutdown_menu_item = gtk.MenuItem(_('Shutdown')) shutdown_menu_item.connect('activate', self._shutdown_activate_cb) - palette.append_menu_item(shutdown_menu_item) + palette.menu.append(shutdown_menu_item) shutdown_menu_item.show() self.set_palette(palette) diff --git a/shell/view/home/activitiesdonut.py b/shell/view/home/activitiesdonut.py index 0c690b2e..28c4c087 100644 --- a/shell/view/home/activitiesdonut.py +++ b/shell/view/home/activitiesdonut.py @@ -88,14 +88,14 @@ class ActivityIcon(CanvasIcon): resume_menu_item = gtk.MenuItem(_('Resume')) resume_menu_item.connect('activate', self._resume_activate_cb) - palette.append_menu_item(resume_menu_item) + palette.menu.append(resume_menu_item) resume_menu_item.show() # FIXME: kludge if self._activity.get_type() != "org.laptop.JournalActivity": stop_menu_item = gtk.MenuItem(_('Stop')) stop_menu_item.connect('activate', self._stop_activate_cb) - palette.append_menu_item(stop_menu_item) + palette.menu.append(stop_menu_item) stop_menu_item.show() def _launching_changed_cb(self, activity, pspec): diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 9d578773..4d09499c 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -96,24 +96,30 @@ class Palette(gtk.Window): self._label = gtk.Label() vbox.pack_start(self._label, False) + self._secondary_box = gtk.VBox() + vbox.pack_start(self._secondary_box) + self._separator = gtk.HSeparator() - vbox.pack_start(self._separator) + self._secondary_box.pack_start(self._separator) menu_box = gtk.VBox() - vbox.pack_start(menu_box) + self._secondary_box.pack_start(menu_box) menu_box.show() self._content = gtk.VBox() - vbox.pack_start(self._content) + self._secondary_box.pack_start(self._content) + self._content.show() self._button_bar = gtk.HButtonBox() - vbox.pack_start(self._button_bar) + self._secondary_box.pack_start(self._button_bar) + self._button_bar.show() self.add(vbox) vbox.show() - self._menu = _sugaruiext.Menu() - self._menu.embed(menu_box) + self.menu = _Menu(self) + self.menu.embed(menu_box) + self.menu.show() self.connect('enter-notify-event', self._enter_notify_event_cb) @@ -129,18 +135,15 @@ class Palette(gtk.Window): self._label.set_text(label) self._label.show() - def append_menu_item(self, item): - self._menu.append(item) - - def insert_menu_item(self, item, index=-1): - self._menu.insert(item, index) - - def remove_menu_item(self, index): - self._menu.remove(self._menu.get_children()[index]) - def set_content(self, widget): + if len(self._content.get_children()) > 0: + self.remove(self._content.get_children()[0]) + + if widget is not None: + self._content.add(widget) + self._update_accept_focus() - self._content.pack_start(widget) + self._update_separator() def append_button(self, button): self._button_bar.append_button(button) @@ -172,6 +175,11 @@ class Palette(gtk.Window): else: raise AssertionError + def _update_separator(self): + visible = len(self.menu.get_children()) > 0 or \ + len(self._content.get_children()) > 0 + self._separator.props.visible = visible + def _update_accept_focus(self): accept_focus = len(self._content.get_children()) if self.window: @@ -308,7 +316,7 @@ class Palette(gtk.Window): 'popup', self._palette_observer_popup_cb) self._update_position() - self._menu.set_active(True) + self.menu.set_active(True) self.show() self._up = True @@ -319,7 +327,7 @@ class Palette(gtk.Window): if not self._palette_popup_sid is None: _palette_observer.disconnect(self._palette_popup_sid) self._palette_popup_sid = None - self._menu.set_active(False) + self.menu.set_active(False) self.hide() self._up = False @@ -344,22 +352,9 @@ class Palette(gtk.Window): return if state == self._PRIMARY: - self._menu.hide() - self._content.hide() - self._separator.hide() - self._button_bar.hide() + self._secondary_box.hide() elif state == self._SECONDARY: - has_menu_items = len(self._menu.get_children()) > 0 - self._menu.props.visible = has_menu_items - - has_content = len(self._content.get_children()) > 0 - self._content.props.visible = has_content - - has_buttons = len(self._button_bar.get_children()) > 0 - self._button_bar.props.visible = has_buttons - - has_separator = has_buttons or has_menu_items or has_content - self._separator.props.visible = has_separator + self._secondary_box.show() self._state = state @@ -382,6 +377,17 @@ class Palette(gtk.Window): if self != palette: self._hide() +class _Menu(_sugaruiext.Menu): + __gtype_name__ = 'SugarPaletteMenu' + + def __init__(self, palette): + _sugaruiext.Menu.__init__(self) + self._palette = palette + + def do_insert(self, item, position): + _sugaruiext.Menu.do_insert(self, item, position) + self._palette._update_separator() + class _PopupAnimation(animator.Animation): def __init__(self, palette): animator.Animation.__init__(self, 0.0, 1.0) From 6ae38464156c5ba2c06826ab9d8b9d4bd226c2bb Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 13:03:09 +0200 Subject: [PATCH 11/13] Expose palette.action_bar --- sugar/graphics/palette.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 4d09499c..a8774880 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -110,9 +110,9 @@ class Palette(gtk.Window): self._secondary_box.pack_start(self._content) self._content.show() - self._button_bar = gtk.HButtonBox() - self._secondary_box.pack_start(self._button_bar) - self._button_bar.show() + self.action_bar = PaletteActionBar() + self._secondary_box.pack_start(self.action_bar) + self.action_bar.show() self.add(vbox) vbox.show() @@ -145,10 +145,6 @@ class Palette(gtk.Window): self._update_accept_focus() self._update_separator() - def append_button(self, button): - self._button_bar.append_button(button) - self._button_bar.show() - def set_group_id(self, group_id): if self._group_id: group = palettegroup.get_group(self._group_id) @@ -377,6 +373,18 @@ class Palette(gtk.Window): if self != palette: self._hide() +class PaletteActionBar(gtk.HButtonBox): + def add_action(label, icon_name=None): + button = Button(label) + + if icon_name: + icon = Icon(icon_name) + button.set_image(icon) + icon.show() + + self.pack_start(button) + button.show() + class _Menu(_sugaruiext.Menu): __gtype_name__ = 'SugarPaletteMenu' From 1145f0f99c727656a6d0772255da6b5e03abd3f6 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 14:41:30 +0200 Subject: [PATCH 12/13] Override menu shell deactivate to go through the palette. --- sugar/graphics/palette.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index a8774880..70e27f9a 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -396,6 +396,9 @@ class _Menu(_sugaruiext.Menu): _sugaruiext.Menu.do_insert(self, item, position) self._palette._update_separator() + def do_deactivate(self): + self._palette._hide() + class _PopupAnimation(animator.Animation): def __init__(self, palette): animator.Animation.__init__(self, 0.0, 1.0) From 670eb981acf958437a50569009f45b162cd77060 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 8 Aug 2007 14:56:43 +0200 Subject: [PATCH 13/13] Ignore only INFERIOR enter/leave events. --- sugar/graphics/palette.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index 70e27f9a..e8532024 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -361,12 +361,12 @@ class Palette(gtk.Window): self.popdown() def _enter_notify_event_cb(self, widget, event): - if event.detail == gtk.gdk.NOTIFY_NONLINEAR: + if event.detail != gtk.gdk.NOTIFY_INFERIOR: self._popdown_anim.stop() self._secondary_anim.start() def _leave_notify_event_cb(self, widget, event): - if event.detail == gtk.gdk.NOTIFY_NONLINEAR: + if event.detail != gtk.gdk.NOTIFY_INFERIOR: self.popdown() def _palette_observer_popup_cb(self, observer, palette):