Пример #1
0
// Synchronization command format:
// [<DDECOMMAND_SYNC>(["<pdffile>",]"<srcfile>",<line>,<col>[,<newwindow>,<setfocus>])]
static const WCHAR *HandleSyncCmd(const WCHAR *cmd, DDEACK& ack)
{
    ScopedMem<WCHAR> pdfFile, srcFile;
    BOOL line = 0, col = 0, newWindow = 0, setFocus = 0;
    const WCHAR *next = str::Parse(cmd, L"[" DDECOMMAND_SYNC L"(\"%S\",%? \"%S\",%u,%u)]",
                                   &pdfFile, &srcFile, &line, &col);
    if (!next)
        next = str::Parse(cmd, L"[" DDECOMMAND_SYNC L"(\"%S\",%? \"%S\",%u,%u,%u,%u)]",
                          &pdfFile, &srcFile, &line, &col, &newWindow, &setFocus);
    // allow to omit the pdffile path, so that editors don't have to know about
    // multi-file projects (requires that the PDF has already been opened)
    if (!next) {
        pdfFile.Set(NULL);
        next = str::Parse(cmd, L"[" DDECOMMAND_SYNC L"(\"%S\",%u,%u)]",
                          &srcFile, &line, &col);
        if (!next)
            next = str::Parse(cmd, L"[" DDECOMMAND_SYNC L"(\"%S\",%u,%u,%u,%u)]",
                              &srcFile, &line, &col, &newWindow, &setFocus);
    }

    if (!next)
        return NULL;

    WindowInfo *win = NULL;
    if (pdfFile) {
        // check if the PDF is already opened
        win = FindWindowInfoByFile(pdfFile);
        // if not then open it
        if (newWindow || !win) {
            LoadArgs args(pdfFile, !newWindow ? win : NULL);
            win = LoadDocument(args);
        } else if (win && !win->IsDocLoaded()) {
            ReloadDocument(win);
        }
    }
    else {
        // check if any opened PDF has sync information for the source file
        win = FindWindowInfoBySyncFile(srcFile);
        if (newWindow) {
            LoadArgs args(win->loadedFilePath);
            win = LoadDocument(args);
        }
    }

    if (!win || !win->IsDocLoaded())
        return next;
    if (!win->pdfsync)
        return next;

    ack.fAck = 1;
    assert(win->IsDocLoaded());
    UINT page;
    Vec<RectI> rects;
    int ret = win->pdfsync->SourceToDoc(srcFile, line, col, &page, rects);
    ShowForwardSearchResult(win, srcFile, line, col, ret, page, rects);
    if (setFocus)
        win->Focus();

    return next;
}
Пример #2
0
// Jump to page DDE command. Format:
// [<DDECOMMAND_PAGE>("<pdffilepath>", <page number>)]
static const WCHAR *HandlePageCmd(const WCHAR *cmd, DDEACK& ack)
{
    ScopedMem<WCHAR> pdfFile;
    UINT page;
    const WCHAR *next = str::Parse(cmd, L"[" DDECOMMAND_PAGE L"(\"%S\",%u)]",
                                   &pdfFile, &page);
    if (!next)
        return false;

    // check if the PDF is already opened
    WindowInfo *win = FindWindowInfoByFile(pdfFile);
    if (!win)
        return next;
    if (!win->IsDocLoaded()) {
        ReloadDocument(win);
        if (!win->IsDocLoaded())
            return next;
    }

    if (!win->dm->ValidPageNo(page))
        return next;

    win->dm->GoToPage(page, 0, true);
    ack.fAck = 1;
    win->Focus();
    return next;
}
Пример #3
0
static HTREEITEM AddTocItemToView(HWND hwnd, DocTocItem *entry, HTREEITEM parent, bool toggleItem)
{
    TV_INSERTSTRUCT tvinsert;
    tvinsert.hParent = parent;
    tvinsert.hInsertAfter = TVI_LAST;
    tvinsert.itemex.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE;
    tvinsert.itemex.state = entry->child && entry->open != toggleItem ? TVIS_EXPANDED : 0;
    tvinsert.itemex.stateMask = TVIS_EXPANDED;
    tvinsert.itemex.lParam = (LPARAM)entry;
    // Replace unprintable whitespace with regular spaces
    str::NormalizeWS(entry->title);
    tvinsert.itemex.pszText = entry->title;

#ifdef DISPLAY_TOC_PAGE_NUMBERS
    WindowInfo *win = FindWindowInfoByHwnd(hwnd);
    if (entry->pageNo && win && win->IsDocLoaded() && !win->AsEbook()) {
        ScopedMem<WCHAR> label(win->ctrl->GetPageLabel(entry->pageNo));
        ScopedMem<WCHAR> text(str::Format(L"%s  %s", entry->title, label));
        tvinsert.itemex.pszText = text;
        return TreeView_InsertItem(hwnd, &tvinsert);
    }
#endif

    return TreeView_InsertItem(hwnd, &tvinsert);
}
Пример #4
0
// Open file DDE command, format:
// [<DDECOMMAND_OPEN>("<pdffilepath>"[,<newwindow>,<setfocus>,<forcerefresh>])]
static const WCHAR *HandleOpenCmd(const WCHAR *cmd, DDEACK& ack)
{
    ScopedMem<WCHAR> pdfFile;
    BOOL newWindow = 0, setFocus = 0, forceRefresh = 0;
    const WCHAR *next = str::Parse(cmd, L"[" DDECOMMAND_OPEN L"(\"%S\")]", &pdfFile);
    if (!next)
        next = str::Parse(cmd, L"[" DDECOMMAND_OPEN L"(\"%S\",%u,%u,%u)]",
                          &pdfFile, &newWindow, &setFocus, &forceRefresh);
    if (!next)
        return NULL;

    WindowInfo *win = FindWindowInfoByFile(pdfFile);
    if (newWindow || !win) {
        LoadArgs args(pdfFile, !newWindow ? win : NULL);
        win = LoadDocument(args);
    } else if (win && !win->IsDocLoaded()) {
        ReloadDocument(win);
        forceRefresh = 0;
    }

    assert(!win || !win->IsAboutWindow());
    if (!win)
        return next;

    ack.fAck = 1;
    if (forceRefresh)
        ReloadDocument(win, true);
    if (setFocus)
        win->Focus();

    return next;
}
Пример #5
0
void LinkHandler::LaunchFile(const WCHAR *path, PageDestination *link)
{
    // for safety, only handle relative paths and only open them in SumatraPDF
    // (unless they're of an allowed perceived type) and never launch any external
    // file in plugin mode (where documents are supposed to be self-contained)
    WCHAR drive;
    if (str::StartsWith(path, L"\\") || str::Parse(path, L"%c:\\", &drive) || gPluginMode) {
        return;
    }

    ScopedMem<WCHAR> fullPath(path::GetDir(owner->dm->FilePath()));
    fullPath.Set(path::Join(fullPath, path));
    fullPath.Set(path::Normalize(fullPath));
    // TODO: respect link->ld.gotor.new_window for PDF documents ?
    WindowInfo *newWin = FindWindowInfoByFile(fullPath);
    // TODO: don't show window until it's certain that there was no error
    if (!newWin) {
        LoadArgs args(fullPath, owner);
        newWin = LoadDocument(args);
        if (!newWin)
            return;
    }

    if (!newWin->IsDocLoaded()) {
        CloseWindow(newWin, true);
        // OpenFileExternally rejects files we'd otherwise
        // have to show a notification to be sure (which we
        // consider bad UI and thus simply don't)
        bool ok = OpenFileExternally(fullPath);
        if (!ok) {
            ScopedMem<WCHAR> msg(str::Format(_TR("Error loading %s"), fullPath));
            ShowNotification(owner, msg, true /* autoDismiss */, true /* highlight */);
        }
        return;
    }

    newWin->Focus();
    if (!link)
        return;

    ScopedMem<WCHAR> name(link->GetDestName());
    if (!name)
        newWin->linkHandler->ScrollTo(link);
    else {
        PageDestination *dest = newWin->dm->engine->GetNamedDest(name);
        if (dest) {
            newWin->linkHandler->ScrollTo(dest);
            delete dest;
        }
    }
}
Пример #6
0
Doc GetDocForWindow(SumatraWindow& win)
{
    if (win.AsWindowInfo()) {
        WindowInfo *iwin = win.AsWindowInfo();
        if (!iwin->IsDocLoaded())
            return Doc();
        return Doc(iwin->dm->engine, iwin->dm->engineType);
    }
    if (win.AsEbookWindow()) {
        EbookWindow *ewin = win.AsEbookWindow();
        return ewin->ebookController->GetDoc();
    }
    CrashIf(true);
    return Doc();
}
Пример #7
0
void StressTest::OnTimer(int timerIdGot)
{
    CrashIf(timerId != timerIdGot);
    KillTimer(win->hwndFrame, timerId);
    if (!win->IsDocLoaded()) {
        if (!GoToNextFile()) {
            Finished(true);
            return;
        }
        TickTimer();
        return;
    }

    // chm documents aren't rendered and we block until we show them
    // so we can assume previous page has been shown and go to next page
    if (!win->AsFixed()) {
        if (!GoToNextPage())
            return;
        goto Next;
    }

    // For non-image files, we detect if a page was rendered by checking the cache
    // (but we don't wait more than 3 seconds).
    // Image files are always fully rendered in WM_PAINT, so we know the page
    // has already been rendered.
    DisplayModel *dm = win->AsFixed();
    bool didRender = gRenderCache.Exists(dm, currPage, dm->GetRotation());
    if (!didRender && dm->ShouldCacheRendering(currPage)) {
        double timeInMs = currPageRenderTime.GetTimeInMs();
        if (timeInMs > 3.0 * 1000) {
            if (!GoToNextPage())
                return;
        }
    }
    else if (!GoToNextPage()) {
        return;
    }
    MakeRandomSelection(win, currPage);

Next:
    TickTimer();
}
Пример #8
0
// note: used from CrashHandler.cpp, should not allocate memory
void GetStressTestInfo(str::Str<char>* s)
{
    // only add paths to files encountered during an explicit stress test
    // (for privacy reasons, users should be able to decide themselves
    // whether they want to share what files they had opened during a crash)
    if (!IsStressTesting())
        return;

    for (size_t i = 0; i < gWindows.Count(); i++) {
        WindowInfo *w = gWindows.At(i);
        if (!w || !w->IsDocLoaded() || !w->loadedFilePath)
            continue;

        s->Append("File: ");
        char buf[256];
        str::conv::ToCodePageBuf(buf, dimof(buf), w->loadedFilePath, CP_UTF8);
        s->Append(buf);
        w->stressTest->GetLogInfo(s);
        s->Append("\r\n");
    }
}
Пример #9
0
static WindowInfo *LoadOnStartup(const TCHAR *filePath, CommandLineInfo& i, bool isFirstWin)
{
    bool showWin = !(i.printDialog && i.exitOnPrint) && !gPluginMode;
    LoadArgs args(filePath, NULL, showWin);
    WindowInfo *win = LoadDocument(args);
    if (!win)
        return win;

    if (win->IsDocLoaded() && i.destName && isFirstWin) {
        win->linkHandler->GotoNamedDest(i.destName);
    } else if (win->IsDocLoaded() && i.pageNumber > 0 && isFirstWin) {
        if (win->dm->ValidPageNo(i.pageNumber))
            win->dm->GoToPage(i.pageNumber, 0);
    }
    if (i.hwndPluginParent)
        MakePluginWindow(*win, i.hwndPluginParent);
    if (!win->IsDocLoaded() || !isFirstWin)
        return win;

    if (i.enterPresentation || i.enterFullscreen)
        EnterFullscreen(*win, i.enterPresentation);
    if (i.startView != DM_AUTOMATIC)
        SwitchToDisplayMode(win, i.startView);
    if (i.startZoom != INVALID_ZOOM)
        ZoomToSelection(win, i.startZoom);
    if (i.startScroll.x != -1 || i.startScroll.y != -1) {
        ScrollState ss = win->dm->GetScrollState();
        ss.x = i.startScroll.x;
        ss.y = i.startScroll.y;
        win->dm->SetScrollState(ss);
    }
    if (i.forwardSearchOrigin && i.forwardSearchLine && win->pdfsync) {
        UINT page;
        Vec<RectI> rects;
            ScopedMem<TCHAR> sourcePath(path::Normalize(i.forwardSearchOrigin));
        int ret = win->pdfsync->SourceToDoc(sourcePath, i.forwardSearchLine, 0, &page, rects);
        ShowForwardSearchResult(win, sourcePath, i.forwardSearchLine, 0, ret, page, rects);
    }
    return win;
}
Пример #10
0
 virtual void Execute() {
     if (!WindowInfoStillValid(win))
         return;
     SetForegroundWindow(win->hwndFrame);
     if (win->IsDocLoaded()) {
         if (-1 != pageNo)
             win->dm->GoToPage(pageNo, 0, true);
         // we might have been invoked by clicking on a tree view
         // switch focus so that keyboard navigation works, which enables
         // a fluid experience
         SetFocus(win->hwndFrame);
     }
 }
Пример #11
0
// Jump to named destination DDE command. Command format:
// [<DDECOMMAND_GOTO>("<pdffilepath>", "<destination name>")]
static const WCHAR *HandleGotoCmd(const WCHAR *cmd, DDEACK& ack)
{
    ScopedMem<WCHAR> pdfFile, destName;
    const WCHAR *next = str::Parse(cmd, L"[" DDECOMMAND_GOTO L"(\"%S\",%? \"%S\")]",
                                   &pdfFile, &destName);
    if (!next)
        return NULL;

    WindowInfo *win = FindWindowInfoByFile(pdfFile);
    if (!win)
        return next;
    if (!win->IsDocLoaded()) {
        ReloadDocument(win);
        if (!win->IsDocLoaded())
            return next;
    }

    win->linkHandler->GotoNamedDest(destName);
    ack.fAck = 1;
    win->Focus();
    return next;
}
Пример #12
0
// Set view mode and zoom level. Format:
// [<DDECOMMAND_SETVIEW>("<pdffilepath>", "<view mode>", <zoom level>[, <scrollX>, <scrollY>])]
static const WCHAR *HandleSetViewCmd(const WCHAR *cmd, DDEACK& ack)
{
    ScopedMem<WCHAR> pdfFile, viewMode;
    float zoom = INVALID_ZOOM;
    PointI scroll(-1, -1);
    const WCHAR *next = str::Parse(cmd, L"[" DDECOMMAND_SETVIEW L"(\"%S\",%? \"%S\",%f)]",
                                   &pdfFile, &viewMode, &zoom);
    if (!next)
        next = str::Parse(cmd, L"[" DDECOMMAND_SETVIEW L"(\"%S\",%? \"%S\",%f,%d,%d)]",
                          &pdfFile, &viewMode, &zoom, &scroll.x, &scroll.y);
    if (!next)
        return NULL;

    WindowInfo *win = FindWindowInfoByFile(pdfFile);
    if (!win)
        return next;
    if (!win->IsDocLoaded()) {
        ReloadDocument(win);
        if (!win->IsDocLoaded())
            return next;
    }

    DisplayMode mode = DisplayModeConv::EnumFromName(viewMode, DM_AUTOMATIC);
    if (mode != DM_AUTOMATIC)
        SwitchToDisplayMode(win, mode);

    if (zoom != INVALID_ZOOM)
        ZoomToSelection(win, zoom);

    if (scroll.x != -1 || scroll.y != -1) {
        ScrollState ss = win->dm->GetScrollState();
        ss.x = scroll.x;
        ss.y = scroll.y;
        win->dm->SetScrollState(ss);
    }

    ack.fAck = 1;
    return next;
}
Пример #13
0
void StressTest::Finished(bool success) {
    win->stressTest = nullptr; // make sure we're not double-deleted

    if (success) {
        int secs = SecsSinceSystemTime(stressStartTime);
        AutoFreeW tm(FormatTime(secs));
        AutoFreeW s(str::Format(L"Stress test complete, rendered %d files in %s", filesCount, tm));
        win->ShowNotification(s, NOS_PERSIST, NG_STRESS_TEST_SUMMARY);
    }

    CloseWindow(win, exitWhenDone && MayCloseWindow(win));
    delete this;
}
Пример #14
0
void StressTest::Finished(bool success)
{
    win->stressTest = NULL; // make sure we're not double-deleted

    if (success) {
        int secs = SecsSinceSystemTime(stressStartTime);
        ScopedMem<WCHAR> tm(FormatTime(secs));
        ScopedMem<WCHAR> s(str::Format(L"Stress test complete, rendered %d files in %s", filesCount, tm));
        win->ShowNotification(s, false, false, NG_STRESS_TEST_SUMMARY);
    }

    CloseWindow(win, exitWhenDone);
    delete this;
}
Пример #15
0
void StressTest::Start(const WCHAR* path, const WCHAR* filter, const WCHAR* ranges, int cycles) {
    if (file::Exists(path)) {
        FilesProvider* filesProvider = new FilesProvider(path);
        ParsePageRanges(ranges, pageRanges);
        Start(filesProvider, cycles);
    } else if (dir::Exists(path)) {
        DirFileProvider* dirFileProvider = new DirFileProvider(path, filter);
        ParsePageRanges(ranges, fileRanges);
        Start(dirFileProvider, cycles);
    } else {
        // Note: string dev only, don't translate
        AutoFreeW s(str::Format(L"Path '%s' doesn't exist", path));
        win->ShowNotification(s, NOS_WARNING, NG_STRESS_TEST_SUMMARY);
        Finished(false);
    }
}
Пример #16
0
bool StressTest::GoToNextPage()
{
    double pageRenderTime = currPageRenderTime.GetTimeInMs();
    ScopedMem<WCHAR> s(str::Format(L"Page %d rendered in %d milliseconds", currPage, (int)pageRenderTime));
    win->ShowNotification(s, NOS_DEFAULT, NG_STRESS_TEST_BENCHMARK);

    ++currPage;
    while (!IsInRange(pageRanges, currPage) && currPage <= win->ctrl->PageCount()) {
        currPage++;
    }

    if (currPage > win->ctrl->PageCount()) {
        if (GoToNextFile())
            return true;
        Finished(true);
        return false;
    }

    win->ctrl->GoToPage(currPage, false);
    currPageRenderTime.Start();

    // start text search when we're in the middle of the document, so that
    // search thread touches both pages that were already rendered and not yet
    // rendered
    // TODO: it would be nice to also randomize search starting page but the
    // current API doesn't make it easy
    if (currPage == pageForSearchStart) {
        // use text that is unlikely to be found, so that we search all pages
        win::SetText(win->hwndFindBox, L"!z_yt");
        FindTextOnThread(win, FIND_FORWARD, true);
    }

    if (1 == rand() % 3) {
        ClientRect rect(win->hwndFrame);
        int deltaX = (rand() % 40) - 23;
        rect.dx += deltaX;
        if (rect.dx < 300)
            rect.dx += (abs(deltaX) * 3);
        int deltaY = (rand() % 40) - 23;
        rect.dy += deltaY;
        if (rect.dy < 300)
            rect.dy += (abs(deltaY) * 3);
        SendMessage(win->hwndFrame, WM_SIZE, 0, MAKELONG(rect.dx, rect.dy));
    }
    return true;
}
Пример #17
0
static void ShowSearchResult(WindowInfo& win, TextSel *result, bool addNavPt)
{
    CrashIf(0 == result->len || !result->pages || !result->rects);
    if (0 == result->len || !result->pages || !result->rects)
        return;

    if (addNavPt || !win.dm->PageShown(result->pages[0]) ||
        (win.dm->ZoomVirtual() == ZOOM_FIT_PAGE || win.dm->ZoomVirtual() == ZOOM_FIT_CONTENT))
    {
        win.dm->GoToPage(result->pages[0], 0, addNavPt);
    }

    win.dm->textSelection->CopySelection(win.dm->textSearch);
    UpdateTextSelection(&win, false);
    win.dm->ShowResultRectToScreen(result);
    win.RepaintAsync();
}
Пример #18
0
 virtual void Execute() {
     if (!WindowInfoStillValid(win))
         return;
     if (win->findThread != thread) {
         // Race condition: FindTextOnThread/AbortFinding was
         // called after the previous find thread ended but
         // before this FindEndTask could be executed
         return;
     }
     if (!win->IsDocLoaded()) {
         // the UI has already been disabled and hidden
     } else if (textSel) {
         ShowSearchResult(*win, textSel, wasModifiedCanceled);
         ftd->HideUI(true, loopedAround);
     } else {
         // nothing found or search canceled
         ClearSearchResult(win);
         ftd->HideUI(false, !wasModifiedCanceled);
     }
     win->findThread = NULL;
 }
WindowElement::WindowElement(WindowInfo info, QObject *parent) :
    QObject(parent),
    m_title(info.title()),
    m_windowId(info.window())
{
    SystemIconProvider provider;

    if (info.icon())
        m_pixmap = QPixmap::fromX11Pixmap(info.icon());
    else if (!info.iconName().isEmpty())
    {
        m_pixmap = provider.requestPixmap(info.iconName(), NULL, QSize());
    }
    else
    {
        // App icon wasn't set, and iconName wasn't set... fallback to default
        m_pixmap = provider.requestPixmap("default", NULL, QSize());
    }

    if (!info.notificationIconName().isEmpty())
    {
        m_notify = provider.requestPixmap(info.notificationIconName(), NULL, QSize());
    }
}
Пример #20
0
void LinkHandler::GotoLink(PageDestination *link)
{
    CrashIf(!owner || owner->linkHandler != this);
    if (!link || !owner->IsDocLoaded())
        return;

    ScopedMem<WCHAR> path(link->GetDestValue());
    PageDestType type = link->GetDestType();
    if (Dest_ScrollTo == type) {
        // TODO: respect link->ld.gotor.new_window for PDF documents ?
        ScrollTo(link);
    }
    else if (Dest_LaunchURL == type) {
        if (!path)
            /* ignore missing URLs */;
        else {
            WCHAR *colon = str::FindChar(path, ':');
            WCHAR *hash = str::FindChar(path, '#');
            if (!colon || (hash && colon > hash)) {
                // treat relative URIs as file paths (without fragment identifier)
                if (hash)
                    *hash = '\0';
                // LaunchFile will reject unsupported file types
                LaunchFile(path, NULL);
            }
            else {
                // LaunchBrowser will reject unsupported URI schemes
                LaunchBrowser(path);
            }
        }
    }
    else if (Dest_LaunchEmbedded == type) {
        // open embedded PDF documents in a new window
        if (path && str::StartsWith(path.Get(), owner->ctrl->FilePath())) {
            WindowInfo *newWin = FindWindowInfoByFile(path, true);
            if (!newWin) {
                LoadArgs args(path, owner);
                newWin = LoadDocument(args);
            }
            if (newWin)
                newWin->Focus();
        }
        // offer to save other attachments to a file
        else {
            LinkSaver linkSaverTmp(*owner, path);
            link->SaveEmbedded(linkSaverTmp);
        }
    }
    else if (Dest_LaunchFile == type) {
        if (path) {
            // LaunchFile only opens files inside SumatraPDF
            // (except for allowed perceived file types)
            LaunchFile(path, link);
        }
    }
    // predefined named actions
    else if (Dest_NextPage == type)
        owner->ctrl->GoToNextPage();
    else if (Dest_PrevPage == type)
        owner->ctrl->GoToPrevPage();
    else if (Dest_FirstPage == type)
        owner->ctrl->GoToFirstPage();
    else if (Dest_LastPage == type)
        owner->ctrl->GoToLastPage();
    // Adobe Reader extensions to the spec, cf. http://www.tug.org/applications/hyperref/manual.html
    else if (Dest_FindDialog == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_FIND_FIRST, 0);
    else if (Dest_FullScreen == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_VIEW_PRESENTATION_MODE, 0);
    else if (Dest_GoBack == type)
        owner->ctrl->Navigate(-1);
    else if (Dest_GoForward == type)
        owner->ctrl->Navigate(1);
    else if (Dest_GoToPageDialog == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_GOTO_PAGE, 0);
    else if (Dest_PrintDialog == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_PRINT, 0);
    else if (Dest_SaveAsDialog == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_SAVEAS, 0);
    else if (Dest_ZoomToDialog == type)
        PostMessage(owner->hwndFrame, WM_COMMAND, IDM_ZOOM_CUSTOM, 0);
    else
        CrashIf(Dest_None != type);
}
Пример #21
0
bool StressTest::OpenFile(const TCHAR *fileName)
{
    bool reuse = rand() % 3 != 1;
    _tprintf(_T("%s\n"), fileName);
    fflush(stdout);
    LoadArgs args(fileName, NULL, true /* show */, reuse);
    WindowInfo *w = LoadDocument(args);
    if (!w)
        return false;

    if (w == win) { // WindowInfo reused
        if (!win->dm)
            return false;
    } else if (!w->dm) { // new WindowInfo
        CloseWindow(w, false, true);
        return false;
    }

    // transfer ownership of stressTest object to a new window and close the
    // current one
    assert(this == win->stressTest);
    if (w != win) {
        if (win->IsDocLoaded()) {
            // try to provoke a crash in RenderCache cleanup code
            ClientRect rect(win->hwndFrame);
            rect.Inflate(rand() % 10, rand() % 10);
            SendMessage(win->hwndFrame, WM_SIZE, 0, MAKELONG(rect.dx, rect.dy));
            win->RenderPage(1);
            win->RepaintAsync();
        }

        WindowInfo *toClose = win;
        w->stressTest = win->stressTest;
        win->stressTest = NULL;
        win = w;
        CloseWindow(toClose, false, false);
    }
    if (!win->dm)
        return false;

    win->dm->ChangeDisplayMode(DM_CONTINUOUS);
    win->dm->ZoomTo(ZOOM_FIT_PAGE);
    win->dm->GoToFirstPage();
    if (win->tocVisible || gGlobalPrefs.favVisible)
        SetSidebarVisibility(win, win->tocVisible, gGlobalPrefs.favVisible);

    currPage = pageRanges.At(0).start;
    win->dm->GoToPage(currPage, 0);
    currPageRenderTime.Start();
    ++filesCount;

    pageForSearchStart = (rand() % win->dm->PageCount()) + 1;
    // search immediately in single page documents
    if (1 == pageForSearchStart) {
        // use text that is unlikely to be found, so that we search all pages
        win::SetText(win->hwndFindBox, _T("!z_yt"));
        FindTextOnThread(win);
    }

    int secs = SecsSinceSystemTime(stressStartTime);
    ScopedMem<TCHAR> tm(FormatTime(secs));
    ScopedMem<TCHAR> s(str::Format(_T("File %d: %s, time: %s"), filesCount, fileName, tm));
    ShowNotification(win, s, false, false, NG_STRESS_TEST_SUMMARY);

    return true;
}
Пример #22
0
bool StressTest::OpenFile(const WCHAR* fileName) {
    wprintf(L"%s\n", fileName);
    fflush(stdout);

    LoadArgs args(fileName);
    args.forceReuse = rand() % 3 != 1;
    WindowInfo* w = LoadDocument(args);
    if (!w)
        return false;

    if (w == win) { // WindowInfo reused
        if (!win->IsDocLoaded())
            return false;
    } else if (!w->IsDocLoaded()) { // new WindowInfo
        CloseWindow(w, false);
        return false;
    }

    // transfer ownership of stressTest object to a new window and close the
    // current one
    AssertCrash(this == win->stressTest);
    if (w != win) {
        if (win->IsDocLoaded()) {
            // try to provoke a crash in RenderCache cleanup code
            ClientRect rect(win->hwndFrame);
            rect.Inflate(rand() % 10, rand() % 10);
            SendMessage(win->hwndFrame, WM_SIZE, 0, MAKELONG(rect.dx, rect.dy));
            if (win->AsFixed())
                win->cbHandler->RequestRendering(1);
            win->RepaintAsync();
        }

        WindowInfo* toClose = win;
        w->stressTest = win->stressTest;
        win->stressTest = nullptr;
        win = w;
        CloseWindow(toClose, false);
    }
    if (!win->IsDocLoaded())
        return false;

    win->ctrl->SetDisplayMode(DM_CONTINUOUS);
    win->ctrl->SetZoomVirtual(ZOOM_FIT_PAGE, nullptr);
    win->ctrl->GoToFirstPage();
    if (win->tocVisible || gGlobalPrefs->showFavorites)
        SetSidebarVisibility(win, win->tocVisible, gGlobalPrefs->showFavorites);

    currPage = pageRanges.at(0).start;
    win->ctrl->GoToPage(currPage, false);
    currPageRenderTime.Start();
    ++filesCount;

    pageForSearchStart = (rand() % win->ctrl->PageCount()) + 1;
    // search immediately in single page documents
    if (1 == pageForSearchStart) {
        // use text that is unlikely to be found, so that we search all pages
        win::SetText(win->hwndFindBox, L"!z_yt");
        FindTextOnThread(win, TextSearchDirection::Forward, true);
    }

    int secs = SecsSinceSystemTime(stressStartTime);
    AutoFreeW tm(FormatTime(secs));
    AutoFreeW s(str::Format(L"File %d: %s, time: %s", filesCount, fileName, tm));
    win->ShowNotification(s, NOS_PERSIST, NG_STRESS_TEST_SUMMARY);

    return true;
}
Пример #23
0
static int process_event(XEvent* event) {
    KeySym sym;

    WindowInfo* info = find_handle(event->xany.window);

    if (!info)
        return 1;

    if (event->type == ClientMessage) {
        if ((Atom)event->xclient.data.l[0] == s_wm_delete_window) {
            info->update = 0;
            mfb_close(info);

            return 0;
        }
    }

    switch (event->type) 
    {
        case KeyPress:
        {
            sym = XLookupKeysym(&event->xkey, 0);

			if (handle_special_keys(info, event, 1))
				break;

            if (info->key_callback)
                info->key_callback(info->rust_data, sym, 1);

            if (info->char_callback) {
				unsigned int t = keySym2Unicode(sym);
				if (t != -1)
					info->char_callback(info->rust_data, t);
            }

            break;
        }

        case KeyRelease:
        {
			if (handle_special_keys(info, event, 0))
				break;

            sym = XLookupKeysym(&event->xkey, 0);

            if (info->key_callback)
                info->key_callback(info->rust_data, sym, 0);
            break;
        }

        case ButtonPress:
        {
            if (!info->shared_data)
                break;

            if (event->xbutton.button == Button1)
                info->shared_data->state[0] = 1;
            else if (event->xbutton.button == Button2)
                info->shared_data->state[1] = 1;
            else if (event->xbutton.button == Button3)
                info->shared_data->state[2] = 1;
            else if (event->xbutton.button == Button4)
                info->shared_data->scroll_y = 10.0f;
            else if (event->xbutton.button == Button5)
                info->shared_data->scroll_y = -10.0f;
            else if (event->xbutton.button == Button6)
                info->shared_data->scroll_x = 10.0f;
            else if (event->xbutton.button == Button7)
                info->shared_data->scroll_y = -10.0f;

            break;
        }

        case ButtonRelease:
        {
            if (!info->shared_data)
                break;

            if (event->xbutton.button == Button1) 
                info->shared_data->state[0] = 0;
            else if (event->xbutton.button == Button2)
                info->shared_data->state[1] = 0;
            else if (event->xbutton.button == Button3)
                info->shared_data->state[2] = 0;

            break;
        }

        case ConfigureNotify:
        {
            info->width = event->xconfigure.width;
            info->height = event->xconfigure.height;
            break;
        }
    }

    return 1;
}
Пример #24
0
static void RelayoutTocItem(LPNMTVCUSTOMDRAW ntvcd)
{
    // code inspired by http://www.codeguru.com/cpp/controls/treeview/multiview/article.php/c3985/
    LPNMCUSTOMDRAW ncd = &ntvcd->nmcd;
    HWND hTV = ncd->hdr.hwndFrom;
    HTREEITEM hItem = (HTREEITEM)ncd->dwItemSpec;
    RECT rcItem;
    if (0 == ncd->rc.right - ncd->rc.left || 0 == ncd->rc.bottom - ncd->rc.top)
        return;
    if (!TreeView_GetItemRect(hTV, hItem, &rcItem, TRUE))
        return;
    if (rcItem.right > ncd->rc.right)
        rcItem.right = ncd->rc.right;

    // Clear the label
    RECT rcFullWidth = rcItem;
    rcFullWidth.right = ncd->rc.right;
    FillRect(ncd->hdc, &rcFullWidth, GetSysColorBrush(COLOR_WINDOW));

    // Get the label's text
    WCHAR szText[MAX_PATH];
    TVITEM item;
    item.hItem = hItem;
    item.mask = TVIF_TEXT | TVIF_PARAM;
    item.pszText = szText;
    item.cchTextMax = MAX_PATH;
    TreeView_GetItem(hTV, &item);

    // Draw the page number right-aligned (if there is one)
    WindowInfo *win = FindWindowInfoByHwnd(hTV);
    DocTocItem *tocItem = (DocTocItem *)item.lParam;
    ScopedMem<WCHAR> label;
    if (tocItem->pageNo && win && win->IsDocLoaded()) {
        label.Set(win->ctrl->GetPageLabel(tocItem->pageNo));
        label.Set(str::Join(L"  ", label));
    }
    if (label && str::EndsWith(item.pszText, label)) {
        RECT rcPageNo = rcFullWidth;
        InflateRect(&rcPageNo, -2, -1);

        SIZE txtSize;
        GetTextExtentPoint32(ncd->hdc, label, str::Len(label), &txtSize);
        rcPageNo.left = rcPageNo.right - txtSize.cx;

        SetTextColor(ncd->hdc, GetSysColor(COLOR_WINDOWTEXT));
        SetBkColor(ncd->hdc, GetSysColor(COLOR_WINDOW));
        DrawText(ncd->hdc, label, -1, &rcPageNo, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);

        // Reduce the size of the label and cut off the page number
        rcItem.right = std::max(rcItem.right - txtSize.cx, 0);
        szText[str::Len(szText) - str::Len(label)] = '\0';
    }

    SetTextColor(ncd->hdc, ntvcd->clrText);
    SetBkColor(ncd->hdc, ntvcd->clrTextBk);

    // Draw the focus rectangle (including proper background color)
    HBRUSH brushBg = CreateSolidBrush(ntvcd->clrTextBk);
    FillRect(ncd->hdc, &rcItem, brushBg);
    DeleteObject(brushBg);
    if ((ncd->uItemState & CDIS_FOCUS))
        DrawFocusRect(ncd->hdc, &rcItem);

    InflateRect(&rcItem, -2, -1);
    DrawText(ncd->hdc, szText, -1, &rcItem, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_WORD_ELLIPSIS);
}
Пример #25
0
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    int retCode = 1;    // by default it's error

#ifdef DEBUG
    // Memory leak detection (only enable _CRTDBG_LEAK_CHECK_DF for
    // regular termination so that leaks aren't checked on exceptions,
    // aborts, etc. where some clean-up might not take place)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF);
    //_CrtSetBreakAlloc(421);
    TryLoadMemTrace();
#endif

    DisableDataExecution();
    // ensure that C functions behave consistently under all OS locales
    // (use Win32 functions where localized input or output is desired)
    setlocale(LC_ALL, "C");
    // don't show system-provided dialog boxes when accessing files on drives
    // that are not mounted (e.g. a: drive without floppy or cd rom drive
    // without a cd).
    SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);

#if defined(DEBUG) || defined(SVN_PRE_RELEASE_VER)
    if (str::StartsWith(lpCmdLine, "/tester")) {
        extern int TesterMain(); // in Tester.cpp
        return TesterMain();
    }

    if (str::StartsWith(lpCmdLine, "/regress")) {
        extern int RegressMain(); // in Regress.cpp
        return RegressMain();
    }
#endif
#ifdef SUPPORTS_AUTO_UPDATE
    if (str::StartsWith(lpCmdLine, "-autoupdate")) {
        bool quit = AutoUpdateMain();
        if (quit)
            return 0;
    }
#endif

    srand((unsigned int)time(NULL));

    // load uiautomationcore.dll before installing crash handler (i.e. initializing
    // dbghelp.dll), so that we get function names/offsets in GetCallstack()
    uia::Initialize();
#ifdef DEBUG
    dbghelp::RememberCallstackLogs();
#endif

    SetupCrashHandler();

    ScopedOle ole;
    InitAllCommonControls();
    ScopedGdiPlus gdiPlus(true);
    mui::Initialize();
    uitask::Initialize();

    prefs::Load();

    CommandLineInfo i(GetCommandLine());

    SetCurrentLang(i.lang ? i.lang : gGlobalPrefs->uiLanguage);

    // This allows ad-hoc comparison of gdi, gdi+ and gdi+ quick when used
    // in layout
#if 0
    RedirectIOToConsole();
    BenchEbookLayout(L"C:\\kjk\\downloads\\pg12.mobi");
    system("pause");
    goto Exit;
#endif

    if (i.showConsole) {
        RedirectIOToConsole();
        RedirectDllIOToConsole();
    }
    if (i.makeDefault)
        AssociateExeWithPdfExtension();
    if (i.pathsToBenchmark.Count() > 0) {
        BenchFileOrDir(i.pathsToBenchmark);
        if (i.showConsole)
            system("pause");
    }
    if (i.exitImmediately)
        goto Exit;
    gCrashOnOpen = i.crashOnOpen;

    gPolicyRestrictions = GetPolicies(i.restrictedUse);
    GetFixedPageUiColors(gRenderCache.textColor, gRenderCache.backgroundColor);
    DebugGdiPlusDevice(gUseGdiRenderer);

    if (!RegisterWinClass())
        goto Exit;

    CrashIf(hInstance != GetModuleHandle(NULL));
    if (!InstanceInit(nCmdShow))
        goto Exit;

    if (i.hwndPluginParent) {
        if (!SetupPluginMode(i))
            goto Exit;
    }

    if (i.printerName) {
        // note: this prints all PDF files. Another option would be to
        // print only the first one
        for (size_t n = 0; n < i.fileNames.Count(); n++) {
            bool ok = PrintFile(i.fileNames.At(n), i.printerName, !i.silent, i.printSettings);
            if (!ok)
                retCode++;
        }
        --retCode; // was 1 if no print failures, turn 1 into 0
        goto Exit;
    }

    bool showStartPage = i.fileNames.Count() == 0 && gGlobalPrefs->rememberOpenedFiles && gGlobalPrefs->showStartPage;
    if (showStartPage) {
        // make the shell prepare the image list, so that it's ready when the first window's loaded
        SHFILEINFO sfi;
        SHGetFileInfo(L".pdf", 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
    }

    if (gGlobalPrefs->reopenOnce) {
        WStrVec moreFileNames;
        ParseCmdLine(gGlobalPrefs->reopenOnce, moreFileNames);
        moreFileNames.Reverse();
        for (WCHAR **fileName = moreFileNames.IterStart(); fileName; fileName = moreFileNames.IterNext()) {
            i.fileNames.Append(*fileName);
        }
        moreFileNames.RemoveAt(0, moreFileNames.Count());
        str::ReplacePtr(&gGlobalPrefs->reopenOnce, NULL);
    }

    HANDLE hMutex = NULL;
    HWND hPrevWnd = NULL;
    if (i.printDialog || i.stressTestPath || gPluginMode) {
        // TODO: pass print request through to previous instance?
    }
    else if (i.reuseDdeInstance) {
        hPrevWnd = FindWindow(FRAME_CLASS_NAME, NULL);
    }
    else if (gGlobalPrefs->reuseInstance || gGlobalPrefs->useTabs) {
        hPrevWnd = FindPrevInstWindow(&hMutex);
    }
    if (hPrevWnd) {
        for (size_t n = 0; n < i.fileNames.Count(); n++) {
            OpenUsingDde(hPrevWnd, i.fileNames.At(n), i, 0 == n);
        }
        goto Exit;
    }

    WindowInfo *win = NULL;
    for (size_t n = 0; n < i.fileNames.Count(); n++) {
        win = LoadOnStartup(i.fileNames.At(n), i, !win);
        if (!win) {
            retCode++;
            continue;
        }
        if (i.printDialog)
            OnMenuPrint(win, i.exitWhenDone);
    }
    if (i.fileNames.Count() > 0 && !win) {
        // failed to create any window, even though there
        // were files to load (or show a failure message for)
        goto Exit;
    }
    if (i.printDialog && i.exitWhenDone)
        goto Exit;

    if (!win) {
        win = CreateAndShowWindowInfo();
        if (!win)
            goto Exit;
    }

    UpdateUITextForLanguage(); // needed for RTL languages
    if (win->IsAboutWindow()) {
        // TODO: shouldn't CreateAndShowWindowInfo take care of this?
        UpdateToolbarAndScrollbarState(*win);
    }

    // Make sure that we're still registered as default,
    // if the user has explicitly told us to be
    if (gGlobalPrefs->associatedExtensions)
        RegisterForPdfExtentions(win->hwndFrame);

    if (i.stressTestPath) {
        // don't save file history and preference changes
        gPolicyRestrictions = (gPolicyRestrictions | Perm_RestrictedUse) & ~Perm_SavePreferences;
        RebuildMenuBarForWindow(win);
        StartStressTest(&i, win, &gRenderCache);
    }

    if (gGlobalPrefs->checkForUpdates)
        UpdateCheckAsync(win, true);

    // only hide newly missing files when showing the start page on startup
    if (showStartPage && gFileHistory.Get(0)) {
        gFileExistenceChecker = new FileExistenceChecker();
        gFileExistenceChecker->Start();
    }
    // call this once it's clear whether Perm_SavePreferences has been granted
    prefs::RegisterForFileChanges();

    retCode = RunMessageLoop();

    SafeCloseHandle(&hMutex);
    CleanUpThumbnailCache(gFileHistory);

Exit:
    prefs::UnregisterForFileChanges();

    while (gWindows.Count() > 0) {
        DeleteWindowInfo(gWindows.At(0));
    }

#ifndef DEBUG

    // leave all the remaining clean-up to the OS
    // (as recommended for a quick exit)
    ExitProcess(retCode);

#else

    DeleteObject(GetDefaultGuiFont());
    DeleteBitmap(gBitmapReloadingCue);
    DeleteSplitterBrush();

    // wait for FileExistenceChecker to terminate
    // (which should be necessary only very rarely)
    while (gFileExistenceChecker) {
        Sleep(10);
        uitask::DrainQueue();
    }

    mui::Destroy();
    uitask::Destroy();
    trans::Destroy();

    SaveCallstackLogs();
    dbghelp::FreeCallstackLogs();

    // must be after uitask::Destroy() because we might have queued prefs::Reload()
    // which crashes if gGlobalPrefs is freed
    gFileHistory.UpdateStatesSource(NULL);
    DeleteGlobalPrefs(gGlobalPrefs);

    // it's still possible to crash after this (destructors of static classes,
    // atexit() code etc.) point, but it's very unlikely
    UninstallCrashHandler();

    // output leaks after all destructors of static objects have run
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    return retCode;
#endif
}
Пример #26
0
static int process_event(XEvent* event) {
	KeySym sym;

	WindowInfo* info = find_handle(event->xany.window);

	if (!info)
		return 1;

	if (event->type == ClientMessage) {
		if ((Atom)event->xclient.data.l[0] == s_wm_delete_window) {
			info->update = 0;
			mfb_close(info);

			return 0;
		}
	}

	switch (event->type) 
	{
		case KeyPress:
		{
  			sym = XLookupKeysym(&event->xkey, 0);

			if (info->key_callback)
				info->key_callback(info->rust_data, sym, 1);

			break;
		}

		case KeyRelease:
		{
  			sym = XLookupKeysym(&event->xkey, 0);

			if (info->key_callback)
				info->key_callback(info->rust_data, sym, 0);
			break;
		}

		case ButtonPress:
        {
        	if (!info->shared_data)
        		break;

            if (event->xbutton.button == Button1)
            	info->shared_data->state[0] = 1;
            else if (event->xbutton.button == Button2)
            	info->shared_data->state[1] = 1;
            else if (event->xbutton.button == Button3)
            	info->shared_data->state[2] = 1;
            else if (event->xbutton.button == Button4)
            	info->shared_data->scroll_y = 10.0f;
            else if (event->xbutton.button == Button5)
            	info->shared_data->scroll_y = -10.0f;
            else if (event->xbutton.button == Button6)
            	info->shared_data->scroll_x = 10.0f;
            else if (event->xbutton.button == Button7)
            	info->shared_data->scroll_y = -10.0f;

            break;
		}

		case ButtonRelease:
        {
        	if (!info->shared_data)
        		break;

            if (event->xbutton.button == Button1) 
            	info->shared_data->state[0] = 0;
            else if (event->xbutton.button == Button2)
            	info->shared_data->state[1] = 0;
            else if (event->xbutton.button == Button3)
            	info->shared_data->state[2] = 0;

            break;
		}
	}

	return 1;
}