Make a window redraw itself with Core Graphics?

I developed an injection system and connected some quartz API to create nice effects with windows in Mac OS X. For example, when a user sets the color to red in the window .. it is red glossy red.

But, when I add to an already running application, I can’t give it the desired effects, since the window is already painted. So, I'm looking for something in the quartz / main chart that can allow me to redraw the whole window or some technique that can allow me to send some kind of event / call some function that will make the system redraw the whole window again.

I mean, every thing in the window needs to be painted again so that my connected API is executed to create the correct effects, shades and colors. The order of creation and coloring of the window is very important here.

I am using a technique similar to inject & interpose , and the injection code is C / C ++ code.

Does anyone have an idea how I can achieve this?

+6
source share
3 answers

-[NSView setNeedsDisplayInRect:] and -[NSView setNeedsDisplay:] are the direct equivalents of invalidateRect .

I don't know what you mean by this what you need in Quartz / CoreGraphics. Cocoa already uses them for drawing.

If you want to call some kind of magic function CGxxx (), which will make the window tint again, this is not possible. The title and frame of the window are colored by the system, but as for the content, lower-level APIs cannot know what should be written there. The only one who knows how to draw a presentation is the look itself. (Something may have been cached in the window store, but I don’t know of any public or undocumented APIs to access it).

Everything you find should be based on the request of the NSWindow object to redraw its views. If you already enter a process, it may include the following steps:

  • determining obj-c runtime (you will need at least objc_msgSend )
  • NSApplication class definition
  • using +[NSApplication sharedApplication] and -[NSApplication windows] to find the pointer to the NSWindow* object
  • using contentView , display , etc. for redrawing
+5
source

If you are asking for a way to force a window to redraw itself using a lower level API than Cocoa, then as far as I know, this is not possible. The window is redrawn when the contentRect: content method is called. It goes into CGContextRef to the window, which then uses the method to redraw the window. CoreGraphics is not responsible for redrawing the window. Cocoa uses CoreGraphics to redraw windows.

You can get the window graphic context outside of drawRect: and then draw it whenever you want (see, for example, here ), but it looks like what you really want to do is intercept the results of the usual window drawing procedure and do some of your own things from above. Perhaps you could do this by switching the presentation class of the window contents and overriding drawRect. The helper function for processing the injection will look something like this:

 typedef void (^InjectedBlock)(CGContextRef, CGRect); void InjectIntoView(NSView* view, InjectedBlock aBlock) { Class viewClass = [view class]; InjectedBlock injectedBlock = [aBlock copy]; void(^drawRect)(id, SEL, NSRect) = ^(id self, SEL _cmd, NSRect rect) { struct objc_super superId = { self, viewClass }; objc_msgSendSuper(superId, @selector(drawRect:), rect); injectedBlock([[NSGraphicsContext currentContext] graphicsPort], CGRectFromNSRect(rect)); }; NSString* subclassName = [NSString stringWithFormat:"%s_injected", class_getName(viewClass)] Class subclass objc_allocateClassPair(viewClass, [subclassName UTF8String], 0); objc_registerClassPair(subclass); Method overriddenMethod = class_getInstanceMethod([NSView class], @selector(drawRect:)); IMP imp = imp_implementationWithBlock(drawRect); class_addMethod(subclass, @selector(drawRect:), imp, method_getTypeEncoding(overriddenMethod)) } 

Edit:

Ahhh, you are interested in the whole window. Frame, etc. They are also instances of NSView, but they are private subclasses of NSView that you do not have direct access to. You can force them to redraw by calling display in the window, but this will most likely overwrite everything you did with the window, since it will use the existing procedures for drawing these classes.

So, you can also consider swizzling the drawRect method: these views (calling [[NSGraphicsContext currentContext] graphicsPort] in drawRect: will give you a CGContextRef that you can use with the Quartz API). You can get frame views by calling superview on the window's content view.

Please note that the location of window frame views is undocumented and can be changed using system updates.

It seems like an interesting project!

+5
source

I have not come across something that invalidates the direct, but since your question is how to redraw the full window, it is still not the way you need it.

If invalid, you tell the system that part of your submission is invalid. The next time your system makes available time for drawing (usually immediately after declaring it invalid), it will override the correction that you made invalid.

setNeedsDisplay does the same thing, with the exception of the entire view, and not the specific rectangle inside that view. In your question this does not matter since you want to update the whole window. It connects to the Quartz UIView in the internal system, so your Quartz drawing will also be used if you process it through drawRect, which is called when drawing.

So just call [yourWindow setNeedsDisplay]; and the system will know that your window needs to be redrawn as soon as possible.

+3
source

Source: https://habr.com/ru/post/898586/


All Articles