static LRESULT html_notify_text(html_t* html, UINT code, const WCHAR* text) { /* Note we shamelessly misuse this also for URL notifications, as the * MC_NMHTMLURL and MC_NMHTMLTEXT are binary compatible. * They are separate mainly for historical reasons. */ MC_NMHTMLTEXTW notify; LRESULT res; BOOL need_free = FALSE; HTML_TRACE("html_notify_text: code=%d str='%S'", code, text ? text : L"[null]"); notify.hdr.hwndFrom = html->win; notify.hdr.idFrom = GetDlgCtrlID(html->win); notify.hdr.code = code; if(text == NULL) { notify.pszText = L""; } else if(html->unicode_notifications) { notify.pszText = text; } else { notify.pszText = (WCHAR*) mc_str(text, MC_STRW, MC_STRA); need_free = TRUE; } res = MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, ¬ify); if(need_free) free((WCHAR*)notify.pszText); return res; }
static void html_notify_format(html_t* html) { LRESULT lres; lres = MC_SEND(html->notify_win, WM_NOTIFYFORMAT, html->win, NF_QUERY); html->unicode_notifications = (lres == NFR_UNICODE ? 1 : 0); HTML_TRACE("html_notify_format: Will use %s notifications.", html->unicode_notifications ? "Unicode" : "ANSI"); }
static void grid_notify_format(grid_t* grid) { LRESULT lres; lres = MC_SEND(grid->notify_win, WM_NOTIFYFORMAT, grid->win, NF_QUERY); grid->unicode_notifications = (lres == NFR_UNICODE ? 1 : 0); GRID_TRACE("grid_notify_format: Will use %s notifications.", grid->unicode_notifications ? "Unicode" : "ANSI"); }
static LRESULT button_update_ui_state(HWND win, button_t* button, WPARAM wp, LPARAM lp) { LRESULT ret; DWORD flags; ret = CallWindowProc(orig_button_proc, win, WM_UPDATEUISTATE, wp, lp); flags = MC_SEND(win, WM_QUERYUISTATE, 0, 0); button->hide_focus = (flags & UISF_HIDEFOCUS) ? 1 : 0; button->hide_accel = (flags & UISF_HIDEACCEL) ? 1 : 0; if(!button->no_redraw) InvalidateRect(win, NULL, FALSE); return ret; }
static HBRUSH button_send_ctlcolorbtn(HWND win, HDC dc) { HBRUSH brush; HWND parent = GetAncestor(win, GA_PARENT); if(parent == NULL) parent = win; brush = (HBRUSH) MC_SEND(parent, WM_CTLCOLORBTN, dc, win); if(MC_ERR(brush == NULL)) { /* The parent window procedure does not handle WM_CTLCOLORBTN * correctly. Maybe it forgot to call DefWindowProc? * * Wine-1.1.27/dlls/user32/button.c does this workaround, so * probably they have good reason to do so. Perhaps they noticed * Microsoft standard controls do that too so lets try to be * consistent. */ MC_TRACE("button_send_ctlcolorbtn: Parent window does not handle " "WM_CTLCOLORBTN correctly."); brush = (HBRUSH) DefWindowProc(parent, WM_CTLCOLORBTN, (WPARAM)dc, (LPARAM)win); } return brush; }
static void button_paint_icon(HWND win, button_t* button, HDC dc) { HICON icon; RECT rect; RECT content; int state; SIZE size; UINT flags; HFONT font, old_font; int old_bk_mode; COLORREF old_text_color; HRGN old_clip; /* When theming is not used, we keep all the work on COMCTL32 button * implementation. */ MC_ASSERT(button->theme != NULL); GetClientRect(win, &rect); icon = (HICON) MC_SEND(win, BM_GETIMAGE, IMAGE_ICON, 0); font = (HFONT) MC_SEND(win, WM_GETFONT, 0, 0); if(font == NULL) font = GetStockObject(SYSTEM_FONT); old_font = SelectObject(dc, font); old_bk_mode = GetBkMode(dc); old_text_color = GetTextColor(dc); old_clip = get_clip(dc); /* Draw background */ if(button->style & WS_DISABLED) { state = PBS_DISABLED; } else { LRESULT s = MC_SEND(win, BM_GETSTATE, 0, 0); if(s & BST_PUSHED) state = PBS_PRESSED; else if(s & BST_HOT) state = PBS_HOT; else if(button->style & BS_DEFPUSHBUTTON) state = PBS_DEFAULTED; else state = PBS_NORMAL; } if(mcIsThemeBackgroundPartiallyTransparent(button->theme, BP_PUSHBUTTON, state)) mcDrawThemeParentBackground(win, dc, &rect); mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state, &rect, &rect); /* Get content rectangle of the button and clip DC to it */ mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state, &rect, &content); IntersectClipRect(dc, content.left, content.top, content.right, content.bottom); /* Draw focus rectangle */ if(MC_SEND(win, BM_GETSTATE, 0, 0) & BST_FOCUS) { if(!button->hide_focus) DrawFocusRect(dc, &content); } /* Draw the contents (i.e. the icon) */ if(icon != NULL) { mc_icon_size(icon, &size); flags = DST_ICON; if(button->style & WS_DISABLED) flags |= DSS_DISABLED; DrawState(dc, NULL, NULL, (LPARAM) icon, 0, (rect.right + rect.left - size.cx) / 2, (rect.bottom + rect.top - size.cy) / 2, size.cx, size.cy, flags); } /* Revert DC into original state */ SelectObject(dc, old_font); SetBkMode(dc, old_bk_mode); SetTextColor(dc, old_text_color); SelectObject(dc, old_clip); }
static LRESULT CALLBACK button_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp) { button_t* button = (button_t*) GetWindowLongPtr(win, extra_offset); /* Window procedure for our subclassed BUTTON does some logic if * either [1] the control is split button and system does not support it * (i.e. Windows is older then Vista). * or [2] the control is BS_ICON and theming is in use, as std. * control draws in the old unthemed style this kind of button. * In all other cases all messages are just forwarded to the standard * Microsoft button procedure. */ switch(msg) { case WM_PAINT: case WM_PRINTCLIENT: { BOOL fake_split; BOOL fake_icon; PAINTSTRUCT ps; HDC dc; fake_split = button_is_fake_split(button); fake_icon = button_is_fake_icon(button); if(!fake_split && !fake_icon) { /* Keep it on original proc */ break; } if(msg == WM_PAINT) dc = BeginPaint(win, &ps); else dc = (HDC) wp; if(!button->no_redraw) { if(fake_split) button_paint_split(win, button, dc); else button_paint_icon(win, button, dc); } if(msg == WM_PAINT) EndPaint(win, &ps); return 0; } case WM_LBUTTONDOWN: if(button_is_fake_split(button)) { POINT pt = { GET_X_LPARAM(lp), GET_Y_LPARAM(lp) }; RECT rect; SetFocus(win); GetClientRect(win, &rect); rect.left = rect.right - DROPDOWN_W; if(mc_rect_contains_pt(&rect, &pt)) { /* Handle the click in the drop-down part */ MC_NMBCDROPDOWN notify; button->is_dropdown_pushed = 1; InvalidateRect(win, &rect, TRUE); notify.hdr.hwndFrom = win; notify.hdr.idFrom = GetWindowLong(win, GWL_ID); notify.hdr.code = MC_BCN_DROPDOWN; mc_rect_copy(¬ify.rcButton, &rect); MC_SEND(GetAncestor(win, GA_PARENT), WM_NOTIFY, notify.hdr.idFrom, ¬ify); /* We unpush immediately after the parent handles the * notification. Usually it takes some time - parent * typically shows some popup-menu or other stuff * which includes a modal eventloop and/or mouse capture. */ button->is_dropdown_pushed = 0; InvalidateRect(win, NULL, TRUE); return 0; } } break; case WM_LBUTTONDBLCLK: if(button_is_fake_split(button)) { RECT rect; GetClientRect(win, &rect); rect.left = rect.right - DROPDOWN_W; if(mc_rect_contains_pos(&rect, lp)) { /* We ignore duble-click in the drop-down part. */ return 0; } } break; case WM_GETDLGCODE: /* Handling this message allows the dialogs to set the button * as default, as it is done for normal push buttons. Unfortunately * it causes other problems. See the comment in WM_STYLECHANGING. */ if(button_is_fake_split(button)) { if((button->style & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) { BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_DEFPUSHBUTTON"); return DLGC_BUTTON | DLGC_DEFPUSHBUTTON; } if((button->style & BS_TYPEMASK) == MC_BS_SPLITBUTTON) { BUTTON_TRACE("button_proc(WM_GETDLGCODE): -> DLGC_UNDEFPUSHBUTTON"); return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON; } } break; case BM_SETSTATE: if(button_is_fake_split(button)) { CallWindowProc(orig_button_proc, win, msg, wp, lp); /* USER32.DLL does some painting in BM_SETSTATE. Repaint * the split button. */ InvalidateRect(win, NULL, TRUE); return 0; } break; case BM_GETSTATE: if(button_is_fake_split(button)) { DWORD s = CallWindowProc(orig_button_proc, win, msg, wp, lp); if(button->is_dropdown_pushed) s |= MC_BST_DROPDOWNPUSHED; return s; } break; case BM_SETSTYLE: if(button_is_fake_split(button)) { BUTTON_TRACE("button_proc(BM_SETSTYLE): split style fixup"); wp &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON); wp |= MC_BS_SPLITBUTTON; CallWindowProc(orig_button_proc, win, msg, wp, lp); button->style = GetWindowLong(win, GWL_STYLE); return 0; } break; case WM_SETREDRAW: button->no_redraw = !wp; break; case WM_STYLECHANGING: if(button_is_fake_split(button)) { STYLESTRUCT* ss = (STYLESTRUCT*) lp; if((ss->styleOld & BS_TYPEMASK) == MC_BS_SPLITBUTTON || (ss->styleOld & BS_TYPEMASK) == MC_BS_DEFSPLITBUTTON) { /* On older system which do not support split buttons * (i.e. 2000, XP), the dialog procedure does not handle * moving the default state correctly: It accidentaly * removes our split button button type. Hence we perform * this fixup. * * Unfortunately this means that app. cannot freely change * BS_SPLITBUTTON to BS_BUTTON with SetWindowLong(GWL_STYLE) * as this will prevent that too... */ BUTTON_TRACE("button_proc(WM_STYLECHANGING): split style fixup"); ss->styleNew &= ~(BS_TYPEMASK & ~BS_DEFPUSHBUTTON); ss->styleNew |= MC_BS_SPLITBUTTON; } } break; case WM_STYLECHANGED: if(wp == GWL_STYLE) { STYLESTRUCT* ss = (STYLESTRUCT*) lp; button->style = ss->styleNew; } break; case WM_THEMECHANGED: if(button->theme) mcCloseThemeData(button->theme); button->theme = mcOpenThemeData(win, button_tc); InvalidateRect(win, NULL, FALSE); break; case WM_SYSCOLORCHANGE: InvalidateRect(win, NULL, FALSE); break; case WM_UPDATEUISTATE: button_update_ui_state(button, LOWORD(wp), HIWORD(wp)); InvalidateRect(win, NULL, FALSE); break; case WM_NCCREATE: if(MC_ERR(!CallWindowProc(orig_button_proc, win, WM_NCCREATE, wp, lp))) { MC_TRACE_ERR("button_proc(WM_NCCREATE): orig_button_proc() failed"); return FALSE; } button = (button_t*) malloc(sizeof(button_t)); if(MC_ERR(button == NULL)) { MC_TRACE("button_proc(WM_CREATE): malloc() failed."); return FALSE; } memset(button, 0, sizeof(button_t)); button->style = ((CREATESTRUCT*)lp)->style; SetWindowLongPtr(win, extra_offset, (LONG_PTR) button); return TRUE; case WM_CREATE: if(MC_ERR(CallWindowProc(orig_button_proc, win, WM_CREATE, wp, lp) != 0)) { MC_TRACE_ERR("button_proc(WM_CREATE): orig_button_proc() failed"); return -1; } button->theme = mcOpenThemeData(win, button_tc); { WORD ui_state = MC_SEND(win, WM_QUERYUISTATE, 0, 0); button->hide_focus = (ui_state & UISF_HIDEFOCUS) ? 1 : 0; button->hide_accel = (ui_state & UISF_HIDEACCEL) ? 1 : 0; } return 0; case WM_DESTROY: if(button->theme) { mcCloseThemeData(button->theme); button->theme = NULL; } break; case WM_NCDESTROY: if(button) free(button); break; } return CallWindowProc(orig_button_proc, win, msg, wp, lp); }
static void button_paint_split(HWND win, button_t* button, HDC dc) { RECT rect; RECT rect_left, rect_right; int state_left, state_right; int text_offset = 0; HFONT font, old_font; int old_bk_mode; COLORREF old_text_color; HRGN old_clip; HICON glyph; int width_right = DROPDOWN_W; glyph = ImageList_GetIcon(mc_bmp_glyphs, MC_BMP_GLYPH_MORE_OPTIONS, ILD_TRANSPARENT); GetClientRect(win, &rect); font = (HFONT) MC_SEND(win, WM_GETFONT, 0, 0); if(font == NULL) font = GetStockObject(SYSTEM_FONT); old_font = SelectObject(dc, font); old_bk_mode = GetBkMode(dc); old_text_color = GetTextColor(dc); old_clip = get_clip(dc); /* Draw what's common for left and right parts background. */ if(!button->theme && (button->style & BS_DEFPUSHBUTTON)) { SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME)); Rectangle(dc, rect.left, rect.top, rect.right, rect.bottom); mc_rect_inflate(&rect, -1, -1); width_right--; } /* Setup subrectangles (mainpart 1 and push-down part 2) */ mc_rect_copy(&rect_left, &rect); rect_left.right -= width_right; mc_rect_copy(&rect_right, &rect); rect_right.left = rect_left.right; /* Draw background. */ if(button->theme) { UINT transparent; RECT tmp; /* Determine styles for left and right parts */ if(button->style & WS_DISABLED) { state_left = state_right = PBS_DISABLED; } else { LRESULT state; state = MC_SEND(win, BM_GETSTATE, 0, 0); if(state & MC_BST_DROPDOWNPUSHED) { state_left = PBS_NORMAL; state_right = PBS_PRESSED; } else { if(state & BST_PUSHED) state_left = state_right = PBS_PRESSED; else if(state & BST_HOT) state_left = state_right = PBS_HOT; else if(button->style & BS_DEFPUSHBUTTON) state_left = state_right = PBS_DEFAULTED; else state_left = state_right = PBS_NORMAL; } } /* Handle (semi-)transparent themes. */ transparent = 0; if(mcIsThemeBackgroundPartiallyTransparent(button->theme, BP_PUSHBUTTON, state_left)) transparent |= 0x1; if(mcIsThemeBackgroundPartiallyTransparent(button->theme, BP_PUSHBUTTON, state_right)) transparent |= 0x2; switch(transparent) { case 0x1: mcDrawThemeParentBackground(win, dc, &rect_left); break; case 0x2: mcDrawThemeParentBackground(win, dc, &rect_right); break; case 0x3: mcDrawThemeParentBackground(win, dc, &rect); break; } /* Draw backgrond. */ mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state_left, &rect, &rect_left); mcDrawThemeBackground(button->theme, dc, BP_PUSHBUTTON, state_right, &rect, &rect_right); /* Deflate both rects to content rects only */ mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state_left, &rect_left, &tmp); rect_left.left = tmp.left; rect_left.top = tmp.top; rect_left.bottom = tmp.bottom; mcGetThemeBackgroundContentRect(button->theme, dc, BP_PUSHBUTTON, state_right, &rect_right, &tmp); rect_right.top = tmp.top; rect_right.right = tmp.right; rect_right.bottom = tmp.bottom; /* Draw delimiter of left and right parts. */ rect_right.top += 1; rect_right.bottom -= 1; mcDrawThemeEdge(button->theme, dc, BP_PUSHBUTTON, state_right, &rect_right, BDR_SUNKEN, BF_LEFT, NULL); rect_right.left = tmp.left; } else { /* Determine styles for left and right parts */ if(button->style & WS_DISABLED) { state_left = state_right = DFCS_INACTIVE; } else { LRESULT s = MC_SEND(win, BM_GETSTATE, 0, 0); if(s & MC_BST_DROPDOWNPUSHED) { state_left = 0; state_right = DFCS_PUSHED; } else { if(s & BST_PUSHED) { state_left = state_right = DFCS_PUSHED; } else { state_left = state_right = 0; } } } button_send_ctlcolorbtn(win, dc); /* Draw control edges */ IntersectClipRect(dc, rect_left.left, rect_left.top, rect_left.right, rect_left.bottom); DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH | state_left); SelectClipRgn(dc, NULL); IntersectClipRect(dc, rect_right.left, rect_right.top, rect_right.right, rect_right.bottom); DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH | state_right); /* Parts which are pushed, should have the contents moved a bit */ if(state_left == DFCS_PUSHED) mc_rect_offset(&rect_left, 1, 1); if(state_right == DFCS_PUSHED) mc_rect_offset(&rect_right, 1, 1); /* Draw delimiter */ if(state_left == state_right) { DrawEdge(dc, &rect_right, BDR_SUNKENOUTER | BDR_RAISEDINNER, BF_LEFT | BF_SOFT); } else { rect_right.left--; DrawEdge(dc, &rect_right, BDR_SUNKENOUTER, BF_LEFT | BF_SOFT); rect_right.left++; } /* Adjust for the outer control edges */ mc_rect_inflate(&rect_left, 0, -2); rect_left.left += 2; mc_rect_inflate(&rect_right, -2, -2); } /* Draw focus rectangle. */ if((MC_SEND(win, BM_GETSTATE, 0, 0) & BST_FOCUS) && !button->hide_focus) { SelectClipRgn(dc, NULL); if(button->theme) { mc_rect_set(&rect, rect_left.left, rect_left.top, rect_right.right - DROPDOWN_W, rect_right.bottom); DrawFocusRect(dc, &rect); } else { mc_rect_inflate(&rect_left, -1, -2); DrawFocusRect(dc, &rect_left); mc_rect_inflate(&rect_left, -1, -1); } } /* Draw glyph into the right part */ SelectClipRgn(dc, NULL); IntersectClipRect(dc, rect_right.left, rect_right.top, rect_right.right, rect_right.bottom); DrawIconEx(dc, (rect_right.right + rect_right.left - MC_BMP_GLYPH_W) / 2, (rect_right.bottom + rect_right.top - MC_BMP_GLYPH_H) / 2, glyph, MC_BMP_GLYPH_W, MC_BMP_GLYPH_H, 0, NULL, DI_NORMAL); /* Draw left part contents */ SelectClipRgn(dc, NULL); IntersectClipRect(dc, rect_left.left, rect_left.top, rect_left.right, rect_left.bottom); if(button->style & BS_ICON) { /* Paint (BS_SPLITBUTTON | BS_ICON). Note that this is used even on * Vista, as according to some my testing this style combination * is not supported there... */ HICON icon; icon = (HICON) MC_SEND(win, BM_GETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) 0); if(icon != NULL) { SIZE size; UINT flags; mc_icon_size(icon, &size); flags = DST_ICON; if(button->style & WS_DISABLED) flags |= DSS_DISABLED; DrawState(dc, NULL, NULL, (LPARAM) icon, 0, (rect_left.right + rect_left.left - size.cx) / 2, (rect_left.bottom + rect_left.top - size.cy) / 2, size.cx, size.cy, flags); } } else { /* Paint text label */ TCHAR buffer[256]; int n; UINT flags = 0; /* Setup flags for TextOut/mcDrawThemeText */ switch(button->style & (BS_LEFT | BS_CENTER | BS_RIGHT)) { case BS_LEFT: flags |= DT_LEFT; break; case BS_RIGHT: flags |= DT_RIGHT; break; default: if(GetWindowLong(win, GWL_EXSTYLE) & WS_EX_RIGHT) flags |= DT_RIGHT; else flags |= DT_CENTER; break; } switch(button->style & (BS_TOP | BS_VCENTER | BS_BOTTOM)) { case BS_TOP: flags |= DT_TOP; break; case BS_BOTTOM: flags |= DT_BOTTOM; break; default: flags |= DT_VCENTER; break; } if(button->style & BS_MULTILINE) flags |= DT_WORDBREAK; else flags |= DT_SINGLELINE; if(button->hide_accel) flags |= DT_HIDEPREFIX; n = MC_SEND(win, WM_GETTEXT, MC_ARRAY_SIZE(buffer), buffer); if(button->theme) { mcDrawThemeText(button->theme, dc, BP_PUSHBUTTON, state_left, buffer, n, flags, 0, &rect_left); } else { SetBkMode(dc, TRANSPARENT); SetTextColor(dc, GetSysColor(COLOR_BTNTEXT)); mc_rect_offset(&rect_left, text_offset, text_offset); DrawText(dc, buffer, n, &rect_left, flags); } } SelectObject(dc, old_font); SetBkMode(dc, old_bk_mode); SetTextColor(dc, old_text_color); SelectObject(dc, old_clip); }
BOOL MCTRL_API mcMenubar_HandleRebarChevronPushed(HWND hwndMenubar, NMREBARCHEVRON* lpRebarChevron) { REBARBANDINFO band_info; menubar_t* mb; RECT rect; HMENU menu; MENUITEMINFO mii; TCHAR buffer[MENUBAR_ITEM_LABEL_MAXSIZE]; int i, n; TPMPARAMS params; /* Verify lpRebarChevron is from notification we assume. */ if(MC_ERR(lpRebarChevron->hdr.code != RBN_CHEVRONPUSHED)) { MC_TRACE("mcMenubar_HandleRebarChevronPushed: Not RBN_CHEVRONPUSHED"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* Verify/get the menubar handle */ band_info.cbSize = REBARBANDINFO_V3_SIZE; band_info.fMask = RBBIM_CHILD; MC_SEND(lpRebarChevron->hdr.hwndFrom, RB_GETBANDINFO, lpRebarChevron->uBand, &band_info); if(hwndMenubar != NULL) { if(MC_ERR(hwndMenubar != band_info.hwndChild)) { MC_TRACE("mcMenubar_HandleRebarChevronPushed: " "Notification not about band with the specified menubar."); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } else { hwndMenubar = band_info.hwndChild; if(MC_ERR(hwndMenubar == NULL)) { MC_TRACE("mcMenubar_HandleRebarChevronPushed: " "The band does not host any child window"); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } /* Create popup menu for not completely visible menu items */ mb = (menubar_t*) GetWindowLongPtr(hwndMenubar, extra_offset); GetClientRect(hwndMenubar, &rect); menu = CreatePopupMenu(); if(MC_ERR(menu == NULL)) { MC_TRACE_ERR("mcMenubar_HandleRebarChevronPushed: CreatePopupMenu() failed."); return FALSE; } mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID | MIIM_SUBMENU; mii.dwTypeData = buffer; mii.cch = MC_SIZEOF_ARRAY(buffer); n = MENUBAR_SENDMSG(hwndMenubar, TB_BUTTONCOUNT, 0, 0); for(i = n-1; i >= 0; i--) { RECT item_rect; MENUBAR_SENDMSG(hwndMenubar, TB_GETITEMRECT, i, &item_rect); if(item_rect.right < rect.right) break; mii.cch = MC_SIZEOF_ARRAY(buffer); GetMenuItemInfo(mb->menu, i, TRUE, &mii); InsertMenuItem(menu, 0, TRUE, &mii); } params.cbSize = sizeof(TPMPARAMS); mc_rect_copy(¶ms.rcExclude, &lpRebarChevron->rc); /* Run the menu */ MapWindowPoints(hwndMenubar, NULL, (POINT*) ¶ms.rcExclude, 2); TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL, params.rcExclude.left, params.rcExclude.bottom, mb->win, ¶ms); /* Destroy the popup menu. Note submenus have to survive as they are shared * with the menubar itself. */ n = GetMenuItemCount(menu); for(i = 0; i < n; i++) RemoveMenu(menu, 0, MF_BYPOSITION); DestroyMenu(menu); return TRUE; }
static LRESULT CALLBACK menubar_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp) { menubar_t* mb = (menubar_t*) GetWindowLongPtr(win, extra_offset); switch(msg) { case MC_MBM_REFRESH: lp = (LPARAM)mb->menu; /* no break */ case MC_MBM_SETMENU: return (menubar_set_menu(mb, (HMENU)lp, (msg == MC_MBM_REFRESH)) == 0 ? TRUE : FALSE); case TB_SETPARENT: case CCM_SETNOTIFYWINDOW: { HWND old = mb->notify_win; mb->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT)); return (LRESULT) old; } case WM_COMMAND: MENUBAR_TRACE("menubar_proc(WM_COMMAND): code=%d; wid=%d; control=%p", (int)HIWORD(wp), (int)LOWORD(wp), (HWND)lp); if(lp == 0 && HIWORD(wp) == 0) /* msg came from the menu */ return MC_SEND(mb->notify_win, msg, wp, lp); break; case WM_NOTIFY: { NMHDR* hdr = (NMHDR*) lp; if(hdr->hwndFrom == win) return menubar_notify(mb, hdr); break; } case WM_ENTERMENULOOP: case WM_EXITMENULOOP: case WM_CONTEXTMENU: case WM_INITMENU: case WM_INITMENUPOPUP: case WM_UNINITMENUPOPUP: case WM_MENUSELECT: case WM_MENUCHAR: case WM_MENURBUTTONUP: case WM_MENUCOMMAND: case WM_MENUDRAG: case WM_MENUGETOBJECT: case WM_MEASUREITEM: case WM_DRAWITEM: return MC_SEND(mb->notify_win, msg, wp, lp); case WM_KEYDOWN: case WM_SYSKEYDOWN: if(menubar_key_down(mb, wp, lp)) return 0; break; case WM_GETDLGCODE: return MENUBAR_SENDMSG(win, msg, wp, lp) | DLGC_WANTALLKEYS | DLGC_WANTARROWS; case WM_NCCREATE: if(MC_ERR(MENUBAR_SENDMSG(win, msg, wp, lp) == FALSE)) { MC_TRACE_ERR("menubar_proc: MENUBAR_SENDMSG(WM_NCCREATE) failed"); return FALSE; } mb = menubar_nccreate(win, (CREATESTRUCT*) lp); if(MC_ERR(mb == NULL)) return FALSE; SetWindowLongPtr(win, extra_offset, (LONG_PTR)mb); return TRUE; case WM_SETFOCUS: MENUBAR_TRACE("menubar_proc(WM_SETFOCUS): old focus %p", (HWND) wp); if(win != (HWND) wp) mb->old_focus = (HWND) wp; active_menubar = mb; break; case WM_KILLFOCUS: MENUBAR_TRACE("menubar_proc: WM_KILLFOCUS"); mb->old_focus = NULL; MENUBAR_SENDMSG(mb->win, TB_SETHOTITEM, -1, 0); menubar_update_ui_state(mb, FALSE); active_menubar = NULL; break; case WM_CREATE: return menubar_create(mb, (CREATESTRUCT*) lp); case WM_DESTROY: menubar_destroy(mb); break; case WM_NCDESTROY: if(mb) { menubar_ncdestroy(mb); mb = NULL; } break; /* Disable those standard toolbar messages, which modify contents of * the toolbar, as it is our internal responsibility to set it * according to the menu. */ case TB_ADDBITMAP: case TB_ADDSTRING: MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return -1; case TB_ADDBUTTONS: case TB_BUTTONSTRUCTSIZE: case TB_CHANGEBITMAP: case TB_DELETEBUTTON: case TB_ENABLEBUTTON: case TB_HIDEBUTTON: case TB_INDETERMINATE: case TB_INSERTBUTTON: case TB_LOADIMAGES: case TB_MARKBUTTON: case TB_MOVEBUTTON: case TB_PRESSBUTTON: case TB_REPLACEBITMAP: case TB_SAVERESTORE: case TB_SETANCHORHIGHLIGHT: case TB_SETBITMAPSIZE: case TB_SETBOUNDINGSIZE: case TB_SETCMDID: case TB_SETDISABLEDIMAGELIST: case TB_SETHOTIMAGELIST: case TB_SETIMAGELIST: case TB_SETINSERTMARK: case TB_SETPRESSEDIMAGELIST: case TB_SETSTATE: MC_TRACE("menubar_proc: Suppressing message TB_xxxx (%d)", msg); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; /* FALSE == NULL == 0 */ case TB_CUSTOMIZE: /* Actually we suppress TB_CUSTOMIZE as the message above (i.e. * not passing it into the original proc), but we also misuse * is for our internal purpose of showing the popup menu. */ menubar_perform_dropdown(mb); return 0; } return MENUBAR_SENDMSG(win, msg, wp, lp); }
static LRESULT menubar_notify(menubar_t* mb, NMHDR* hdr) { switch(hdr->code) { case TBN_DROPDOWN: { NMTOOLBAR* info = (NMTOOLBAR*) hdr; MENUBAR_TRACE("menubar_notify(%p, TBN_DROPDOWN, %d)", mb, info->iItem); menubar_dropdown(mb, info->iItem, FALSE); break; } case TBN_HOTITEMCHANGE: { NMTBHOTITEM* info = (NMTBHOTITEM*) hdr; MENUBAR_TRACE("menubar_notify(%p, TBN_HOTITEMCHANGE, %d -> %d)", mb, (info->dwFlags & HICF_ENTERING) ? -1 : info->idOld, (info->dwFlags & HICF_LEAVING) ? -1 : info->idNew); mb->hot_item = (info->dwFlags & HICF_LEAVING) ? -1 : info->idNew; break; } case NM_CUSTOMDRAW: { NMTBCUSTOMDRAW* info = (NMTBCUSTOMDRAW*) hdr; switch(info->nmcd.dwDrawStage) { case CDDS_PREPAINT: if(mc_win_version >= MC_WIN_VISTA && mcIsAppThemed()) return CDRF_DODEFAULT; else if(mc_win_version < MC_WIN_XP) return CDRF_DODEFAULT; else return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: { int text_color_id; int bk_color_id; TCHAR buffer[MENUBAR_ITEM_LABEL_MAXSIZE]; TBBUTTONINFO btn; UINT flags = MENUBAR_DTFLAGS; HDC dc = info->nmcd.hdc; HFONT old_font; if(info->nmcd.uItemState & (CDIS_HOT | CDIS_SELECTED)) { text_color_id = COLOR_HIGHLIGHTTEXT; bk_color_id = COLOR_HIGHLIGHT; } else { text_color_id = COLOR_MENUTEXT; bk_color_id = -1; } btn.cbSize = sizeof(TBBUTTONINFO); btn.dwMask = TBIF_TEXT; btn.pszText = buffer; btn.cchText = MC_SIZEOF_ARRAY(buffer); MENUBAR_SENDMSG(mb->win, TB_GETBUTTONINFO, info->nmcd.dwItemSpec, &btn); if(MENUBAR_SENDMSG(mb->win, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) flags |= DT_HIDEPREFIX; if(bk_color_id >= 0) FillRect(dc, &info->nmcd.rc, (HBRUSH) (INT_PTR) (bk_color_id+1)); SetTextColor(dc, GetSysColor(text_color_id)); old_font = SelectObject(dc, (HFONT) MENUBAR_SENDMSG(mb->win, WM_GETFONT, 0, 0)); SetBkMode(dc, TRANSPARENT); DrawText(dc, buffer, -1, &info->nmcd.rc, flags); SelectObject(dc, old_font); return CDRF_SKIPDEFAULT; } default: return CDRF_DODEFAULT; } } } return MC_SEND(mb->notify_win, WM_NOTIFY, hdr->idFrom, hdr); }
static HRESULT STDMETHODCALLTYPE dispatch_Invoke(IDispatch* self, DISPID disp_id, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* params, VARIANT* var_res, EXCEPINFO* except, UINT* arg_err) { html_t* html = MC_HTML_FROM_DISPTACH(self); switch(disp_id) { case DISPID_BEFORENAVIGATE2: { BSTR url = V_BSTR(V_VARIANTREF(¶ms->rgvarg[5])); VARIANT_BOOL* cancel = V_BOOLREF(¶ms->rgvarg[0]); HTML_TRACE("dispatch_Invoke: DISPID_BEFORENAVIGATE2(%S)", url); if(url != NULL && wcsncmp(url, L"app:", 4) == 0) { html_notify_text(html, MC_HN_APPLINK, url); *cancel = VARIANT_TRUE; } break; } #if 0 /* Unfortunately, IE does not send DISPID_DOCUMENTCOMPLETE * when refreshing the page (e.g. from context menu). So we workaround * via DISPID_PROGRESSCHANGE below. */ case DISPID_DOCUMENTCOMPLETE: { BSTR url = V_BSTR(V_VARIANTREF(¶ms->rgvarg[0])); html_notify_text(html, MC_HN_DOCUMENTCOMPLETE, url); break; } #endif case DISPID_PROGRESSCHANGE: { LONG progress_max = V_I4(¶ms->rgvarg[0]); LONG progress = V_I4(¶ms->rgvarg[1]); MC_NMHTMLPROGRESS notify; HTML_TRACE("dispatch_Invoke: DISPID_PROGRESSCHANGE(%ld, %ld)", progress, progress_max); /* Send also notification about the progress */ notify.hdr.hwndFrom = html->win; notify.hdr.idFrom = GetDlgCtrlID(html->win); notify.hdr.code = MC_HN_PROGRESS; notify.lProgress = progress; notify.lProgressMax = progress_max; MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, ¬ify); /* This replaces DISPID_DOCUMENTCOMPLETE above */ if(progress < 0 || progress_max < 0) { IWebBrowser2* browser_iface; HRESULT hr; hr = html->browser_obj->lpVtbl->QueryInterface(html->browser_obj, &IID_IWebBrowser2, (void**)&browser_iface); if(MC_ERR(hr != S_OK || browser_iface == NULL)) { MC_TRACE("dispatch_Invoke(DISPID_PROGRESSCHANGE): " "QueryInterface(IID_IWebBrowser2) failed [0x%lx]", hr); } else { BSTR url = NULL; hr = browser_iface->lpVtbl->get_LocationURL(browser_iface, &url); if(hr == S_OK && url != NULL) { html_notify_text(html, MC_HN_DOCUMENTCOMPLETE, url); html_SysFreeString(url); } browser_iface->lpVtbl->Release(browser_iface); } } break; } case DISPID_STATUSTEXTCHANGE: HTML_TRACE("dispatch_Invoke: DISPID_STATUSTEXTCHANGE"); html_notify_text(html, MC_HN_STATUSTEXT, V_BSTR(¶ms->rgvarg[0])); break; case DISPID_TITLECHANGE: HTML_TRACE("dispatch_Invoke: DISPID_TITLECHANGE"); html_notify_text(html, MC_HN_TITLETEXT, V_BSTR(¶ms->rgvarg[0])); break; case DISPID_COMMANDSTATECHANGE: { LONG cmd = V_I4(¶ms->rgvarg[1]); HTML_TRACE("dispatch_Invoke: DISPID_COMMANDSTATECHANGE"); if(cmd == CSC_NAVIGATEBACK || cmd == CSC_NAVIGATEFORWARD) { MC_NMHTMLHISTORY notify; BOOL enabled = (V_BOOL(¶ms->rgvarg[0]) != VARIANT_FALSE); if(cmd == CSC_NAVIGATEBACK) html->can_back = enabled; else html->can_forward = enabled; notify.hdr.hwndFrom = html->win; notify.hdr.idFrom = GetDlgCtrlID(html->win); notify.hdr.code = MC_HN_HISTORY; notify.bCanBack = html->can_back; notify.bCanForward = html->can_forward; MC_SEND(html->notify_win, WM_NOTIFY, notify.hdr.idFrom, ¬ify); } break; } case DISPID_NEWWINDOW2: /* This is called instead of DISPID_NEWWINDOW3 on Windows XP SP2 * and older. */ { VARIANT_BOOL* cancel = V_BOOLREF(¶ms->rgvarg[0]); HTML_TRACE("dispatch_Invoke: DISPID_NEWWINDOW2"); if(html_notify_text(html, MC_HN_NEWWINDOW, L"") == 0) { *cancel = VARIANT_TRUE; HTML_TRACE("dispatch_Invoke(DISPID_NEWWINDOW2): Canceled."); } break; } case DISPID_NEWWINDOW3: { BSTR url = V_BSTR(¶ms->rgvarg[0]); VARIANT_BOOL* cancel = V_BOOLREF(¶ms->rgvarg[3]); HTML_TRACE("dispatch_Invoke: DISPID_NEWWINDOW3"); if(html_notify_text(html, MC_HN_NEWWINDOW, url) == 0) { *cancel = VARIANT_TRUE; HTML_TRACE("dispatch_Invoke(DISPID_NEWWINDOW3, '%S'): Canceled.", url); } break; } default: HTML_TRACE("dispatch_Invoke: unsupported disp_id %d", disp_id); return DISP_E_MEMBERNOTFOUND; } return S_OK; }
static LRESULT CALLBACK html_proc(HWND win, UINT msg, WPARAM wp, LPARAM lp) { html_t* html = (html_t*) GetWindowLongPtr(win, 0); if(html != NULL && html->ie_win == NULL) { /* Let's try to subclass IE window. This is very dirty hack, * which allows us to forward keyboard messages properly to * IOleInPlaceActiveObject::TranslateAccelerator(). * * Normally this should be done from main app. loop but we do not * have it under control in the DLL. */ html->ie_win = html_find_ie_window(win); if(html->ie_win != NULL) { HTML_TRACE("html_proc: Subclassing MSIE."); html->ie_proc = (WNDPROC) SetWindowLongPtr(html->ie_win, GWLP_WNDPROC, (LONG_PTR) html_ie_subclass_proc); SetProp(html->ie_win, ie_prop, (HANDLE) html); if(GetFocus() == win) { SetFocus(html->ie_win); MC_SEND(html->ie_win, WM_LBUTTONDOWN, 0, 0); MC_SEND(html->ie_win, WM_LBUTTONUP, 0, 0); } } } switch(msg) { case MC_HM_GOTOURLW: case MC_HM_GOTOURLA: { int res = html_goto_url(html, (const void*)lp, (msg == MC_HM_GOTOURLW)); return (res == 0 ? TRUE : FALSE); } case MC_HM_SETTAGCONTENTSW: case MC_HM_SETTAGCONTENTSA: { int res = html_set_element_contents(html, (void*)wp, (void*)lp, (msg == MC_HM_SETTAGCONTENTSW)); return (res == 0 ? TRUE : FALSE); } case MC_HM_GOBACK: { int res = html_goto_back(html, wp); return (res == 0 ? TRUE : FALSE); } case MC_HM_CANBACK: return ((wp ? html->can_back : html->can_forward) ? TRUE : FALSE); case WM_SIZE: { IWebBrowser2* browser_iface; HRESULT hr; hr = html->browser_obj->lpVtbl->QueryInterface(html->browser_obj, &IID_IWebBrowser2, (void**)&browser_iface); if(hr == S_OK && browser_iface != NULL) { browser_iface->lpVtbl->put_Width(browser_iface, LOWORD(lp)); browser_iface->lpVtbl->put_Height(browser_iface, HIWORD(lp)); browser_iface->lpVtbl->Release(browser_iface); } return 0; } case WM_STYLECHANGED: if(wp == GWL_STYLE) { STYLESTRUCT* ss = (STYLESTRUCT*) lp; html->style = ss->styleNew; RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN); } break; case WM_NOTIFYFORMAT: switch(lp) { case NF_REQUERY: html_notify_format(html); return (html->unicode_notifications ? NFR_UNICODE : NFR_ANSI); case NF_QUERY: return (MC_IS_UNICODE ? NFR_UNICODE : NFR_ANSI); } break; case CCM_SETUNICODEFORMAT: { BOOL tmp = html->unicode_notifications; html->unicode_notifications = (wp != 0); return tmp; } case CCM_GETUNICODEFORMAT: return html->unicode_notifications; case CCM_SETNOTIFYWINDOW: { HWND old = html->notify_win; html->notify_win = (wp ? (HWND) wp : GetAncestor(win, GA_PARENT)); return (LPARAM) old; } case WM_SETFOCUS: if(html->ie_win) { SetFocus(html->ie_win); MC_SEND(html->ie_win, WM_LBUTTONDOWN, 0, 0); MC_SEND(html->ie_win, WM_LBUTTONUP, 0, 0); } return 0; case WM_GETDLGCODE: return DLGC_WANTALLKEYS; case WM_SETTEXT: return FALSE; case WM_GETTEXT: if(wp > 0) ((TCHAR*)lp)[0] = _T('\0'); return 0; case WM_GETTEXTLENGTH: return 0; case WM_NCCREATE: html = html_nccreate(win, (CREATESTRUCT*)lp); if(MC_ERR(html == NULL)) return FALSE; SetWindowLongPtr(win, 0, (LONG_PTR)html); return TRUE; case WM_CREATE: return (html_create(html, (CREATESTRUCT*)lp) == 0 ? 0 : -1); case WM_DESTROY: html_destroy(html); return 0; case WM_NCDESTROY: if(html) html_ncdestroy(html); return 0; } /* Forward keystrokes to the IE */ if(WM_KEYFIRST <= msg && msg <= WM_KEYLAST) { if(html->ie_win) MC_SEND(html->ie_win, msg, wp, lp); return 0; } return DefWindowProc(win, msg, wp, lp); }
static void grid_paint(void* control, HDC dc, RECT* dirty, BOOL erase) { grid_t* grid = (grid_t*) control; RECT client; RECT rect; int header_w, header_h; int old_dc_state; int col0, row0; int x0, y0; int col, row; int col_count = grid->col_count; int row_count = grid->row_count; table_t* table = grid->table; table_cell_t* cell; GRID_TRACE("grid_paint(%p, %d, %d, %d, %d)", grid, dirty->left, dirty->top, dirty->right, dirty->bottom); if(table == NULL && !(grid->style & MC_GS_OWNERDATA)) return; old_dc_state = SaveDC(dc); GetClientRect(grid->win, &client); header_w = grid_header_width(grid); header_h = grid_header_height(grid); if(grid->font != NULL) SelectObject(dc, grid->font); SetBkMode(dc, TRANSPARENT); SetTextColor(dc, RGB(0,0,0)); SelectObject(dc, GetStockObject(BLACK_PEN)); /* Find 1st visible column */ rect.left = header_w - grid->scroll_x; for(col = 0; col < col_count; col++) { rect.right = rect.left + grid_col_width(grid, col); if(rect.right > header_w) { col0 = col; x0 = rect.left; break; } rect.left = rect.right; } /* Find 1st visible row */ rect.top = header_h - grid->scroll_y; for(row = 0; row < row_count; row++) { rect.bottom = rect.top + grid_row_height(grid, row); if(rect.bottom > header_h) { row0 = row; y0 = rect.top; break; } rect.top = rect.bottom; } /* If needed, send MC_GN_ODCACHEHINT */ if(grid->style & MC_GS_OWNERDATA) { WORD col1, row1; rect.right = x0; for(col1 = col0; col1+1 < grid->col_count; col1++) { rect.right += grid_col_width(grid, col1); if(rect.right >= client.right) break; } rect.bottom = y0; for(row1 = row0; row1+1 < grid->row_count; row1++) { rect.bottom += grid_row_height(grid, row1); if(rect.bottom >= client.bottom) break; } if(col0 != grid->cache_hint[0] || row0 != grid->cache_hint[1] || col1 != grid->cache_hint[2] || row1 != grid->cache_hint[3]) { MC_NMGCACHEHINT hint; hint.hdr.hwndFrom = grid->win; hint.hdr.idFrom = GetWindowLong(grid->win, GWL_ID); hint.hdr.code = MC_GN_ODCACHEHINT; hint.wColumnFrom = col0; hint.wRowFrom = row0; hint.wColumnTo = col1; hint.wRowTo = row1; GRID_TRACE("grid_paint: Sending MC_GN_ODCACHEHINT (%hu, %hu, %hu, %hu)", col0, row0, col1, row1); MC_SEND(grid->notify_win, WM_NOTIFY, hint.hdr.idFrom, &hint); grid->cache_hint[0] = col0; grid->cache_hint[1] = row0; grid->cache_hint[2] = col1; grid->cache_hint[3] = row1; } } /* Paint the "dead" top left header cell */ if(header_w > 0 && header_h > 0 && dirty->left < header_w && dirty->top < header_h) { mc_rect_set(&rect, 0, 0, grid->header_width, grid->header_height); mc_clip_set(dc, 0, 0, MC_MIN(header_w, client.right), MC_MIN(header_h, client.bottom)); grid_paint_header_cell(grid, MC_TABLE_HEADER, MC_TABLE_HEADER, NULL, dc, &rect, -1, 0); } /* Paint column headers */ if(header_h > 0 && dirty->top < header_h) { rect.left = x0; rect.top = 0; rect.bottom = header_h; for(col = col0; col < col_count; col++) { rect.right = rect.left + grid_col_width(grid, col); mc_clip_set(dc, MC_MAX(header_w, rect.left), rect.top, MC_MIN(rect.right, client.right), MC_MIN(rect.bottom, client.bottom)); grid_paint_header_cell(grid, col, MC_TABLE_HEADER, (table ? &table->cols[col] : NULL), dc, &rect, col, (grid->style & MC_GS_COLUMNHEADERMASK)); rect.left = rect.right; if(rect.right >= client.right) break; } } /* Paint row headers */ if(header_w > 0 && dirty->left <= header_w) { rect.left = 0; rect.top = y0; rect.right = header_w; for(row = row0; row < row_count; row++) { rect.bottom = rect.top + grid_row_height(grid, row); mc_clip_set(dc, rect.left, MC_MAX(header_h, rect.top), MC_MIN(rect.right, client.right), MC_MIN(rect.bottom, client.bottom)); grid_paint_header_cell(grid, MC_TABLE_HEADER, row, (table ? &table->rows[row] : NULL), dc, &rect, row, (grid->style & MC_GS_ROWHEADERMASK)); rect.top = rect.bottom; if(rect.bottom >= client.bottom) break; } } /* Paint grid lines */ if(!(grid->style & MC_GS_NOGRIDLINES)) { HPEN pen, old_pen; int x, y; mc_clip_set(dc, header_w, header_h, client.right, client.bottom); pen = CreatePen(PS_SOLID, 0, mcGetThemeSysColor(grid->theme_listview, COLOR_3DFACE)); old_pen = SelectObject(dc, pen); x = x0; y = header_h + grid->scroll_y_max - grid->scroll_y; for(col = col0; col < col_count; col++) { x += grid_col_width(grid, col); MoveToEx(dc, x-1, header_h, NULL); LineTo(dc, x-1, y); if(x >= client.right) break; } x = header_w + grid->scroll_x_max - grid->scroll_x; y = y0; for(row = 0; row < row_count; row++) { y += grid_row_height(grid, row); MoveToEx(dc, header_w, y-1, NULL); LineTo(dc, x, y-1); if(y >= client.bottom) break; } SelectObject(dc, old_pen); DeleteObject(pen); } /* Paint grid cells */ rect.top = y0; for(row = row0; row < row_count; row++) { rect.bottom = rect.top + grid_row_height(grid, row); rect.left = x0; for(col = col0; col < col_count; col++) { if(table != NULL) cell = table_cell(table, col, row); else cell = NULL; rect.right = rect.left + grid_col_width(grid, col); grid_paint_cell(grid, col, row, cell, dc, &rect); if(rect.right >= client.right) break; rect.left = rect.right; } if(rect.bottom >= client.bottom) break; rect.top = rect.bottom; } RestoreDC(dc, old_dc_state); }
static void grid_get_dispinfo(grid_t* grid, WORD col, WORD row, table_cell_t* cell, grid_dispinfo_t* di, DWORD mask) { MC_NMGDISPINFO info; MC_ASSERT((mask & ~(MC_TCMF_TEXT | MC_TCMF_VALUE | MC_TCMF_FLAGS)) == 0); /* Use what can be taken from the cell. */ if(cell != NULL) { if(cell->text != MC_LPSTR_TEXTCALLBACK) { di->text = (cell->is_value ? NULL : cell->text); mask &= ~MC_TCMF_TEXT; } di->value = (cell->is_value ? cell->value : NULL); di->flags = cell->flags; mask &= ~(MC_TCMF_VALUE | MC_TCMF_FLAGS); if(mask == 0) return; } /* For the rest data, fire MC_GN_GETDISPINFO notification. */ info.hdr.hwndFrom = grid->win; info.hdr.idFrom = GetWindowLong(grid->win, GWL_ID); info.hdr.code = (grid->unicode_notifications ? MC_GN_GETDISPINFOW : MC_GN_GETDISPINFOA); info.wColumn = col; info.wRow = row; info.cell.fMask = mask; /* Set info.cell members to meaningful values. lParam may be needed by the * app to find the requested data. Other members should be set to some * defaults to deal with broken apps which do not set the asked members. */ if(cell != NULL) { info.cell.pszText = NULL; info.cell.hValue = NULL; info.cell.lParam = cell->lp; info.cell.dwFlags = cell->flags; } else { info.cell.pszText = NULL; info.cell.hValue = NULL; info.cell.lParam = 0; info.cell.dwFlags = 0; } MC_SEND(grid->notify_win, WM_NOTIFY, 0, &info); /* If needed, convert the text from parent to the expected format. */ if(mask & MC_TCMF_TEXT) { if(grid->unicode_notifications == MC_IS_UNICODE) di->text = info.cell.pszText; else di->text = mc_str(info.cell.pszText, (grid->unicode_notifications ? MC_STRW : MC_STRA), MC_STRT); } else { /* Needed even when not asked for because of grid_free_dispinfo() */ di->text = NULL; } /* Small optimization: We do not ask about the corresponding bits in the * mask for these. If not set, the assignment does no hurt and we save few * instructions. */ di->value = info.cell.hValue; di->flags = info.cell.dwFlags; }