Tuesday, December 27, 2011

Scroll NSScrollView to Top

AppKit is old and is not as convenient as UIKit. But we have to use it on Mac app development.

"Scroll a scrollview to top" sounds easy, but actually it isn't. If you assign a documentView to a NSScrollView, you will see it scrolls to the bottom. (Very stupid!) The doc did not mention how to scroll to top. I found a way to control the vertical scroller. I can set the scroller to top, but the scrollView is still at bottom!

This post (http://stackoverflow.com/questions/4506391/nsscrollview-jumping-to-bottom-on-scroll) inspired me. I got the solution (of cause, I post my answer on stackoverflow too):

// Scroll the vertical scroller to top

if ([_scrollView hasVerticalScroller]) {

_scrollView.verticalScroller.floatValue = 0;

}

// Scroll the contentView to top

[_scrollView.contentView scrollToPoint:NSMakePoint(0, ((NSView*)_scrollView.documentView).frame.size.height - _scrollView.contentSize.height)];

Friday, December 09, 2011

Wrong info from proc_pidinfo

proc_pidinfo is a very useful function to get a Mac OS X process's info such as the size of resident memory, consumed CPU time.

However, sometimes, the returned info is not correct. For example, a little process's resident memory becomes 4GB. Apple does not provide any document about this function, and I did not see useful comments in the header files.

I am lucky enough to see code snippet in the Apple open source file: http://www.opensource.apple.com/source/lsof/lsof-28/lsof/dialects/darwin/libproc/dproc.c. When we call proc_pidinfo, we must check the returned value. If the returned value is not identical to the size of output data, the output data is wrong.

      nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &ti, sizeof(ti));
            if (nb <= 0) {
                if (errno == ESRCH)
                    continue;
                if (!Fwarn) {
                    (void) fprintf(stderr, "%s: PID %d information error: %s\n",
                        Pn, pid, strerror(errno));
                }
                continue;
            } else if (nb < sizeof(ti)) {
                (void) fprintf(stderr,
                    "%s: PID %d: proc_pidinfo(PROC_PIDTASKALLINFO);\n",
                    Pn, pid);
                (void) fprintf(stderr,
                    "      too few bytes; expected %ld, got %d\n",
                    sizeof(ti), nb);
                Exit(1);
            }
I checked the processes with correct info. They are all my processes (not system processes). Seems like my app runs in user mode and it does not have privileges to get info of system processes.