Max 5 API Reference
00001 /** 00002 @file 00003 windowwatcher - Demonstrate how to get notifications about the window for a patcher in which an object exists. 00004 Scrolling or sizing can be obtained by attaching to the patcherview to get notifications. 00005 Getting the actual window position requires the "boxscreenrectchanged" method to be added. 00006 00007 @ingroup examples 00008 00009 Copyright 2009 - Cycling '74 00010 Timothy Place, tim@cycling74.com 00011 */ 00012 00013 #include "ext.h" 00014 #include "ext_obex.h" 00015 #include "jpatcher_api.h" 00016 00017 00018 // Data Structures 00019 typedef struct _ww { 00020 t_object w_obj; 00021 t_object *w_patcher; 00022 t_object *w_patcherview; 00023 void *w_outlet; 00024 } t_ww; 00025 00026 00027 // Prototypes 00028 t_ww* ww_new(t_symbol *s, short argc, t_atom *argv); 00029 void ww_free(t_ww *x); 00030 void ww_attach(t_ww *x); 00031 t_max_err ww_notify(t_ww *x, t_symbol *s, t_symbol *msg, void *sender, void *data); 00032 void ww_boxscreenrectchanged(t_jbox *box, t_object *patcherview); 00033 00034 // Globals and Statics 00035 static t_class *s_ww_class = NULL; 00036 00037 00038 /**********************************************************************/ 00039 // Class Definition and Life Cycle 00040 00041 int main(void) 00042 { 00043 t_class *c; 00044 00045 common_symbols_init(); 00046 c = class_new("windowwatcher", (method)ww_new, (method)ww_free, sizeof(t_ww), (method)NULL, A_GIMME, 0L); 00047 00048 class_addmethod(c, (method)ww_notify, "notify", A_CANT, 0); 00049 00050 // If your object were a UI external, then you could simple add the method to the class as below. 00051 // However, this example object is not a UI extern. 00052 00053 // At somepoint in the future instance-methods may be supported. 00054 // If/when they are we cound add a method to our instance in the 'new' method instead. 00055 00056 //class_addmethod(c, (method)ww_boxscreenrectchanged, "boxscreenrectchanged", A_CANT, 0); 00057 00058 class_register(_sym_box, c); 00059 s_ww_class = c; 00060 return 0; 00061 } 00062 00063 00064 t_ww* ww_new(t_symbol *s, short argc, t_atom *argv) 00065 { 00066 t_ww *x = NULL; 00067 t_object *box = NULL; 00068 00069 x = (t_ww*)object_alloc(s_ww_class); 00070 if (x) { 00071 x->w_outlet = outlet_new(x, 0L); 00072 attr_args_process(x, argc, argv); 00073 00074 object_obex_lookup(x, _sym_pound_P, &x->w_patcher); 00075 object_obex_lookup(x, _sym_pound_B, &box); 00076 00077 // If/when instance methods are supported, we can use object_addmethod() to add the method 00078 // (as opposed to a class method) to our box. 00079 // Then we can be called when our box is moved. 00080 object_addmethod(box, (method)ww_boxscreenrectchanged, "boxscreenrectchanged", A_CANT, 0); 00081 00082 // The patcherview is not available when the object is created as a patcher is being read from disk, 00083 // so we have to defer to wait for it before getting it and attaching for notifications. 00084 // if we were in a ui object then we would instead add a 'patcherview_vis' method 00085 // (and possibly a 'patcherview_invis' method) and attach to our patcherview at that time. 00086 defer_low(x, (method)ww_attach, NULL, 0, NULL); 00087 00088 } 00089 return x; 00090 } 00091 00092 00093 void ww_free(t_ww *x) 00094 { 00095 if(x->w_patcherview) 00096 object_detach_byptr((t_object *)x, x->w_patcherview); 00097 } 00098 00099 00100 /**********************************************************************/ 00101 // Methods 00102 00103 void ww_attach(t_ww *x) 00104 { 00105 x->w_patcherview = object_attr_getobj(x->w_patcher, _sym_firstview); 00106 object_attach_byptr_register(x, x->w_patcherview, _sym_nobox); 00107 } 00108 00109 00110 t_max_err ww_notify(t_ww *x, t_symbol *s, t_symbol *msg, void *sender, void *data) 00111 { 00112 t_symbol *name = NULL; 00113 t_rect r; 00114 t_atom a[4]; 00115 00116 if(sender == x->w_patcherview){ 00117 if(msg == _sym_attr_modified){ 00118 name = (t_symbol *)object_method((t_object *)data, _sym_getname); 00119 00120 // the patcherview is notified when its rect changes size 00121 if(name == _sym_rect){ 00122 object_attr_get_rect(x->w_patcherview, _sym_rect, &r); 00123 atom_setfloat(a+0, r.x); 00124 atom_setfloat(a+1, r.y); 00125 atom_setfloat(a+2, r.width); 00126 atom_setfloat(a+3, r.height); 00127 outlet_anything(x->w_outlet, _sym_patcherview, 4, a); 00128 } 00129 // the patcherview is notified when its visible rect has changed (i.e. scrollbars have been moved) 00130 if(name == _sym_visiblecanvasrect){ 00131 object_attr_get_rect(x->w_patcherview, _sym_visiblecanvasrect, &r); 00132 atom_setfloat(a+0, r.x); 00133 atom_setfloat(a+1, r.y); 00134 atom_setfloat(a+2, r.width); 00135 atom_setfloat(a+3, r.height); 00136 outlet_anything(x->w_outlet, _sym_visiblecanvasrect, 4, a); 00137 } 00138 } 00139 else if(msg == _sym_free){ 00140 object_detach_byptr((t_object *)x, x->w_patcherview); 00141 x->w_patcherview = NULL; 00142 } 00143 } 00144 return MAX_ERR_NONE; 00145 } 00146 00147 00148 void ww_boxscreenrectchanged(t_jbox *box, t_object *patcherview) 00149 { 00150 t_rect r; 00151 t_atom a[4]; 00152 t_ww *x = (t_ww *)box->b_firstin; 00153 00154 // This method is an instance method of our box object (newobj) 00155 // So ... 00156 00157 object_attr_get_rect(x->w_patcherview, _sym_rect, &r); 00158 atom_setfloat(a+0, r.x); 00159 atom_setfloat(a+1, r.y); 00160 atom_setfloat(a+2, r.width); 00161 atom_setfloat(a+3, r.height); 00162 outlet_anything(x->w_outlet, _sym_boxscreenrectchanged, 4, a); 00163 } 00164
Copyright © 2008, Cycling '74